2

我正在尝试使用执行器接口实现多线程方法,其中我在主类中生成了多个线程

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())
            {

            }

    }
}

可调用类是

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 所花费的时间相同

所以看起来应用程序运行得和单线程应用程序一样好。请建议我在实现中做错了什么。

谢谢

4

2 回答 2

6

你打电话时

                map = executor.submit(worker);

map在这种情况下返回的值是 a Future。这意味着它没有值,直到可调用对象返回一个值。现在当你打电话

                    iTextRecords.putAll(map.get());

发生的情况是当前线程阻塞(在内部map.get())等待可调用返回(在另一个线程中)。

map.get()由于您总是在提交一个新的 (per ) 之前等待一个可调用对象完成 (per ),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);
 }
于 2013-09-27T11:49:07.090 回答
0

您必须在提交可赎回资产时收集您的期货。仅在完成提交后才在您的期货上调用 get()。

于 2013-09-27T12:18:21.713 回答