我正在尝试使用executor接口实现多线程方法,其中我在主类中产生了多个线程
class Main
{
private static final int NTHREADS = 10;
public static void main(String[] args)
{
.........
String str = createThreads(document);
.............
}
public String createThreads(String docString)
{
........
.......
Map<String,String> iTextRecords = new LinkedHashMap<String, String>();
if(!iText.matches(""))
{
String[] tokenizedItext = iText.split("\\^");
ExecutorService executor = Executors.newFixedThreadPool(NTHREADS);
for(int index = 0 ;index < tokenizedItext.length;index++)
{
Callable<Map<String,String>> worker = null;
Future<Map<String,String>> map = null;
if(tokenizedItext[index].matches("^[0-9.<>+-= ]+$") || tokenizedItext[index].matches("^\\s+$"))
{
iTextRecords.put(tokenizedItext[index],tokenizedItext[index]);
}
else
{
worker = new MultipleDatabaseCallable(tokenizedItext[index],language);
map = executor.submit(worker);
try
{
iTextRecords.putAll(map.get());
}
catch(InterruptedException ex)
{
ex.printStackTrace(System.out);
}
catch(ExecutionException ex)
{
ex.printStackTrace(System.out);
}
}
}
executor.shutdown();
// Wait until all threads are finish
while (!executor.isTerminated())
{
}
}
}
Callable类为
class MultipleDatabaseCallable implements Callable<Map<String,String>>
{
@Override
public Map<String, String> call() throws Exception {
System.out.println("Entering: "+Thread.currentThread().getName());
Map<String,String> map = new HashMap<String,String>();
for(int i =0;i<50000;i++)
{
for(int i1 = 0 ;i1<5000;i1++)
{
for(int i2 =0;i2 <500;i2++)
{
}
}
}
System.out.println("Exiting: "+Thread.currentThread().getName());
return map;
}
}
我得到的输出是
Entering: pool-1-thread-1
Exiting: pool-1-thread-1
Entering: pool-1-thread-2
Exiting: pool-1-thread-2
Entering: pool-1-thread-3
Exiting: pool-1-thread-3
Entering: pool-1-thread-4
Exiting: pool-1-thread-4
Entering: pool-1-thread-5
Exiting: pool-1-thread-5
Entering: pool-1-thread-6
Exiting: pool-1-thread-6
在查看输出时,似乎一次只在调用方法中输入一个线程,而其他线程仅在存在前一个线程时才进入。但是,预计多个线程应该输入并执行call()方法。另外,当我通过使NTHREADS = 1执行相同的程序时,所花费的时间与NTHREADS = 10所花费的时间相同。
所以看起来该应用程序的运行情况与单线程应用程序一样好。请提出我在实现过程中出现的问题。
谢谢
参考方案
您打电话的时候
map = executor.submit(worker);
在这种情况下,返回的map
值为Future
。意味着在可调用对象返回一个值之前,它没有值。现在当你打电话
iTextRecords.putAll(map.get());
发生的情况是当前线程块(在map.get()
内部)等待可调用对象返回(在另一个线程中)。
由于您始终等待可调用对象完成(每个map.get()
),然后再提交一个新对象(每个executor.submit()
),因此可以强制执行观察到的顺序执行。
为了并行执行任务,必须在第一次调用get之前将其全部启动。例如,您可以创建一个ArrayList<Future<Map<String,String>>> futures = ...
然后
做
futures.add(executor.submit(worker));
提交任务(不需要map
变量)并创建第二个循环(在for(int i ...)
循环之后):
for(Future<Map<String,String>> f: futures) {
iTextRecords.putAll(f.get);
}
使用Java RMI调用Python方法 - java我有一个通过Python web2py创建的远程方法。如何测试和调用Java中的方法?我能够测试该方法是否实现@service.xmlrpc,但是如何测试该方法是否实现@service.run? 参考方案 如果您能做到,我会感到惊讶。 Java RMI需要Java对等体。
获取远程机器的系统信息(使用Java) - java正如问题的标题所言,我想使用Java获取远程系统的系统信息(例如OS名称,版本等)。但是,在任何人回答这个问题之前,我只想问一下这是否可能,如果可以,那么如何?还有一个问题是,这对于基于Unix和基于Windows的系统都应适用。我尝试搜索Internet,但是(几乎)空白。编辑:Java应用程序将是一个桌面应用程序,它必须具有凭据才能登录到远程系统,但不会…
使用Java 8流处理null属性,并使用lambda表达式进行排序 - java让我们考虑一个仅包含一个Parent属性的Integer类。我创建了6个父类对象,属性值是100, 20, 300, 400, 500, null。现在,我将所有对象添加到列表中(列表名称为list)。然后,我想获取其属性值大于100的对象。为此,我使用了Java 8流。Predicate<Entity> predicate = e -> …
使用java.util.properties存储ArrayList和HashMap - java如何使用ArrayList存储HashMap和/或java.util.properties变量?如果不可能,可以使用其他什么类来存储应用程序配置? 参考方案 如果只需要将集合序列化为字符串,我强烈建议XStream。它使用反射将类序列化为XML。如果默认行为对您要序列化的类不起作用,则有文档,但是到目前为止,以下内容对我而言一直有效:XStream xstr…
使用Java 8流的if-else条件 - java场景:在某些情况下,我需要使用Java 8流API根据某些字段条件为对象的List设置一些值。下面是对象User的示例。public class User{ private int id; private String name; private String text; private boolean isActive; } 这是我制定的代码List<…