都用与阻塞线程

Join

情景:

假设一条流水线上有三个工作者:worker0,worker1,worker2。有一个任务的完成需要他们三者协作完成,worker2可以开始这个任务的前提是worker0和worker1完成了他们的工作,而worker0和worker1是可以并行他们各自的工作的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    public class Worker extends Thread {  

    //工作者名  
    private String name;  
    //工作时间  
    private long time;  

    public Worker(String name, long time) {  
        this.name = name;  
        this.time = time;  
    }  

    @Override  
    public void run() {  
        // TODO 自动生成的方法存根  
        try {  
            System.out.println(name+"开始工作");  
            Thread.sleep(time);  
            System.out.println(name+"工作完成,耗费时间="+time);  
        } catch (InterruptedException e) {  
            // TODO 自动生成的 catch 块  
            e.printStackTrace();  
        }     
    }  
}

Test类:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public class Test {  

    public static void main(String[] args) throws InterruptedException {  
        // TODO 自动生成的方法存根  

        Worker worker0 = new Worker("worker0", (long) (Math.random()*2000+3000));  
        Worker worker1 = new Worker("worker1", (long) (Math.random()*2000+3000));  
        Worker worker2 = new Worker("worker2", (long) (Math.random()*2000+3000));  

        worker0.start();  
        worker1.start();  

        worker0.join();  
        worker1.join();  
        System.out.println("准备工作就绪");  

        worker2.start();          
    }  
} 

输出:

1
2
3
4
5
6
7
worker1开始工作
worker0开始工作
worker1工作完成,耗费时间=3947
worker0工作完成,耗费时间=4738
准备工作就绪
worker2开始工作
worker2工作完成,耗费时间=4513

CountDownLatch

情景:

假设worker的工作可以分为两个阶段,work2 只需要等待work0和work1完成他们各自工作的第一个阶段之后就可以开始自己的工作了,而不是场景1中的必须等待work0和work1把他们的工作全部完成之后才能开始。

Work类:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class Worker extends Thread {  

    //工作者名  
    private String name;  
    //第一阶段工作时间  
    private long time;  

    private CountDownLatch countDownLatch;  

    public Worker(String name, long time, CountDownLatch countDownLatch) {  
        this.name = name;  
        this.time = time;  
        this.countDownLatch = countDownLatch;  
    }  

    @Override  
    public void run() {  
        // TODO 自动生成的方法存根  
        try {  
            System.out.println(name+"开始工作");  
            Thread.sleep(time);  
            System.out.println(name+"第一阶段工作完成");  

            countDownLatch.countDown();  

            Thread.sleep(2000); //这里就姑且假设第二阶段工作都是要2秒完成  
            System.out.println(name+"第二阶段工作完成");  
            System.out.println(name+"工作完成,耗费时间="+(time+2000));  

        } catch (InterruptedException e) {  
            // TODO 自动生成的 catch 块  
            e.printStackTrace();  
        }     
    }  
}  

Test类:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public class Test {  

    public static void main(String[] args) throws InterruptedException {  
        // TODO 自动生成的方法存根  

        CountDownLatch countDownLatch = new CountDownLatch(2);  
        Worker worker0 = new Worker("worker0", (long) (Math.random()*2000+3000CountDownLatch与join的区别:调用thread.join() 方法必须等thread 执行完毕,当前线程才能继续往下执行,而CountDownLatch通过计数器提供了更灵活的控制,只要检测到计数器为0当前线程就可以往下执行而不用管相应的thread是否执行完毕。), countDownLatch);  
        Worker worker1 = new Worker("worker1", (long) (Math.random()*2000+3000), countDownLatch);  
        Worker worker2 = new Worker("worker2", (long) (Math.random()*2000+3000), countDownLatch);  

        worker0.start();  
        worker1.start();      
        countDownLatch.await();  

        System.out.println("准备工作就绪");  
        worker2.start();  

    }  

输出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
worker0开始工作
worker1开始工作
worker1第一阶段工作完成
worker0第一阶段工作完成
准备工作就绪
worker2开始工作
worker1第二阶段工作完成
worker1工作完成,耗费时间=5521
worker0第二阶段工作完成
worker0工作完成,耗费时间=6147
worker2第一阶段工作完成
worker2第二阶段工作完成
worker2工作完成,耗费时间=5384

CountDownLatch与join的区别:调用thread.join() 方法必须等thread 执行完毕,当前线程才能继续往下执行,而CountDownLatch通过计数器提供了更灵活的控制,只要检测到计数器为0当前线程就可以往下执行而不用管相应的thread是否执行完毕。