在java中使用Countdownlatch和Executor时没有获得预期的输出

时间:2013-02-26 17:35:39

标签: java multithreading executorservice

我是Java 多线程的新手。尝试在Java线程中学习countdownlatch和executor并实现以下代码 -

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorBasicFramework {


    class MyThread extends Thread{

        int iCount ; String name;
        CountDownLatch latch;

        public MyThread(int iCount, String name, CountDownLatch latch) {
            super();
            this.iCount = iCount;
            this.name = name;
            this.latch = latch;         
        }

        @Override
        public void run() {
            for(int i=0;i<10;i++){
                System.out.println(name+" Printing .... "+ ++iCount+" L "+latch.getCount());
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }               
            }
            latch.countDown();

        }

    }

    public ExecutorBasicFramework() {
        createThread();
    }


    private void createThread() {
        ExecutorService exec = Executors.newFixedThreadPool(10);
        CountDownLatch latch = new CountDownLatch(10);
        for(int i=0;i<10;i++){          
            MyThread thread = new MyThread(i*10, ""+i,latch);
            exec.execute(thread);

            try {
                latch.await();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        exec.shutdownNow();     

    }

    public static void main(String[] args) {
        new ExecutorBasicFramework();
    }

}

输出结果为 -

0 Printing .... 1 L 10
0 Printing .... 2 L 10
0 Printing .... 3 L 10
0 Printing .... 4 L 10
0 Printing .... 5 L 10
0 Printing .... 6 L 10
0 Printing .... 7 L 10
0 Printing .... 8 L 10
0 Printing .... 9 L 10
0 Printing .... 10 L 10

然后流程就像继续等待。 我的预期输出如上所述,但是在打印0之后,它应该打印类似的输出1到9然后程序应该停止。

我认为countdownlatch正在等待并等待它不会增加执行者的下一个计数器。所以我无法得到预期的输出。 我期待输出像 -

0 Printing .... 1 L 10
0 Printing .... 2 L 10
0 Printing .... 3 L 10
0 Printing .... 4 L 10
0 Printing .... 5 L 10
0 Printing .... 6 L 10
0 Printing .... 7 L 10
0 Printing .... 8 L 10
0 Printing .... 9 L 10
0 Printing .... 10 L 10


1 Printing .... 11 L 9
1 Printing .... 12 L 9
1 Printing .... 13 L 9
1 Printing .... 14 L 9
1 Printing .... 15 L 9
1 Printing .... 16 L 9
1 Printing .... 17 L 9
1 Printing .... 18 L 9
1 Printing .... 19 L 9
1 Printing .... 20 L 9

and So on ... 
2 Printing .... 21 L 8
2 Printing .... 22 L 8
2 Printing .... 23 L 8
  

与latch的每个递减计数器,下一个线程是池必须   执行计数直到10.然后再次必须减少锁存器   计数器再次重复该过程直到线程9完成   相同

请提出一些意见。

3 个答案:

答案 0 :(得分:3)

因此,您正在配置倒计时值10 new CountDownLatch(10),但您的代码只是每个线程减少一次。在你只分叉1个线程之后,然后等待锁存器,但它位于9。

MyThread thread = new MyThread(i*10, ""+i,latch);
exec.execute(thread);
latch.await();

不确定您的意图但是latch.countDown();可能线程中的for循环中吗?

for(int i=0;i<10;i++) {
   ...
   // if you want the latch to count-down 10 times, it should be inside the loop
   latch.countDown();
}
// it should not go here, outside the loop

如果目标是等待所有作业完成,您可以使用ExecutorService.awaitTermination(...)方法执行此操作:

// submit jobs in loop
exec.shutdown();
exec.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);

此外,应该在Thread课程中展开MyThread。您应该实施Runnable。您的代码有效的唯一原因是Thread也实现了Runnable,但MyThread应该ThreadExecutorService需要RunnableCallable,而不是Thread。它在内部管理服务的线程。

答案 1 :(得分:1)

如果您打算使用CountDownLatchmain()方法等到所有线程都执行完毕,那么您应该将latch.await() 移到之外提交线程的循环。 此外,如果不再设置中断标志,则不应该吃InterruptedException。 (see this article)。

修正如下:

for(int i=0;i<10;i++){          
    MyThread thread = new MyThread(i*10, ""+i,latch);
    exec.execute(thread);
}
try {
    latch.await();
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}

虽然这肯定会有效,但是当使用ExecutorService时,Latch是在另一个线程上等待Runnable执行的次优方式。如果您使用的是submit()而不是execute(),则可以使用Future返回的submit(),通过调用Runnable等待提交的get()完成在它上面。

答案 2 :(得分:0)

感谢大家的投入。 我找到了一个更简单的解决方案来达到我的预期。 我刚刚使用Executors.newSingleThreadExecutor();,因为它已经确保所有任务都能保证按顺序实现。