CountDownLatch和Join都可以让一个线程等待子线程完成的功能,但CountDownLatch比Join的优势在哪呢?下面用示例说明
一、首先举一个Join的使用实例,当然Logger需要自己配置
先是Join类
JoinClass
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JoinClass extends Thread{
final Logger logger = LoggerFactory.getLogger(JoinClass.class);
String name;
JoinClass(String _name) {
name = _name;
}
@Override
public void run() {
try {
logger.info("{} is running",name);
Thread.sleep(2000);
logger.info("{} is over",name);
}catch (InterruptedException e) {
logger.error("{} , ",name,e);
}
}
}
测试方法
Test
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CountDownLatch;
public class Test {
final static Logger logger = LoggerFactory.getLogger(Main.class);
public void JoinClassTest() {
//join类示例
JoinClass j1 = new JoinClass("j1");
JoinClass j2 = new JoinClass("j2");
JoinClass j3 = new JoinClass("j3");
j1.start();
j2.start();
try {
j1.join();
j2.join();
}catch (InterruptedException e) {
logger.error("j1 and j2,",e);
}
logger.info("j1 and j2 are over, j3 start");
j3.start();
}
}
结果
2018-12-03 20:03:39 INFO [CountDownLatchAndJoin.JoinClass] j1 is running
2018-12-03 20:03:39 INFO [CountDownLatchAndJoin.JoinClass] j2 is running
2018-12-03 20:03:41 INFO [CountDownLatchAndJoin.JoinClass] j1 is over
2018-12-03 20:03:41 INFO [CountDownLatchAndJoin.JoinClass] j2 is over
2018-12-03 20:03:41 INFO [CountDownLatchAndJoin.Main] j1 and j2 are over, j3 start
2018-12-03 20:03:41 INFO [CountDownLatchAndJoin.JoinClass] j3 is running
2018-12-03 20:03:43 INFO [CountDownLatchAndJoin.JoinClass] j3 is over
从结果看出使用Join后,主线程在等待 j1 和 j2 执行完成后才去调用 j3线程
二、下面是CountDownLatch使用用例
CountDownLatchSimple类
CountDownLatchClass
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchSimple extends Thread{
final Logger logger = LoggerFactory.getLogger(CountDownLatchSimple.class);
private CountDownLatch countDownLatch;
String name;
CountDownLatchSimple(String _name, CountDownLatch _countDownLatch) {
name = _name;
countDownLatch=_countDownLatch;
}
@Override
public void run() {
try {
logger.info("{} is running",name);
Thread.sleep(2000);
logger.info("{} is over",name);
countDownLatch.countDown();
}catch (InterruptedException e) {
logger.info("{}",name,e);
}
}
}
测试方法
Test
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CountDownLatch;
public class Test {
final static Logger logger = LoggerFactory.getLogger(Main.class);
public void CountDownLatchSimple() {
//CountDownLatch实现
CountDownLatch countDownLatch = new CountDownLatch(2);
CountDownLatchSimple countDownLatch1 = new CountDownLatchSimple("countDownLatch1",countDownLatch);
CountDownLatchSimple countDownLatch2 = new CountDownLatchSimple("countDownLatch2",countDownLatch);
CountDownLatchSimple countDownLatch3 = new CountDownLatchSimple("countDownLatch3",countDownLatch);
countDownLatch1.start();
countDownLatch2.start();
try {
countDownLatch.await();
}catch (InterruptedException e) {
logger.error("countDownLatch.await,",e);
}
countDownLatch3.start();
}
}
测试结果
2018-12-03 20:15:43 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatch2 is running
2018-12-03 20:15:43 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatch1 is running
2018-12-03 20:15:45 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatch1 is over
2018-12-03 20:15:45 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatch2 is over
2018-12-03 20:15:45 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatch3 is running
2018-12-03 20:15:47 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatch3 is over
从结果看出CountDownLatch实现了和Join一样的功能
三、但有些功能是否是Join不能实现的呢?看如下代码
CountDownLatchStage类
CountDownLatchStage
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchStage extends Thread{
final Logger logger = LoggerFactory.getLogger(CountDownLatchSimple.class);
private CountDownLatch countDownLatch;
String name;
CountDownLatchStage(String _name, CountDownLatch _countDownLatch) {
name = _name;
countDownLatch=_countDownLatch;
}
@Override
public void run() {
try {
logger.info("{} is running",name);
Thread.sleep(2000);
logger.info("{}'s finished half of work ",name);
countDownLatch.countDown();
Thread.sleep(1000);
logger.info("{}'s is over,end",name);
}catch (InterruptedException e) {
logger.info("{}",name,e);
}
}
}
Test类
Test
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CountDownLatch;
public class Test {
final static Logger logger = LoggerFactory.getLogger(Main.class);
public void CountDownLatchStage() {
//CountDownLatchStage实现
CountDownLatch countDownLatch = new CountDownLatch(2);
CountDownLatchStage countDownLatchStage1 = new CountDownLatchStage("countDownLatchStage1",countDownLatch);
CountDownLatchStage countDownLatchStage2 = new CountDownLatchStage("countDownLatchStage2",countDownLatch);
CountDownLatchStage countDownLatchStage3 = new CountDownLatchStage("countDownLatchStage3",countDownLatch);
countDownLatchStage1.start();
countDownLatchStage2.start();
try {
countDownLatch.await();
}catch (InterruptedException e) {
logger.error("countDownLatch.await,",e);
}
countDownLatchStage3.start();
}
}
结果
2018-12-03 20:20:50 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage2 is running
2018-12-03 20:20:50 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage1 is running
2018-12-03 20:20:52 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage2’s finished half of work
2018-12-03 20:20:52 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage1’s finished half of work
2018-12-03 20:20:52 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage3 is running
2018-12-03 20:20:53 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage2’s is over,end
2018-12-03 20:20:53 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage1’s is over,end
2018-12-03 20:20:54 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage3’s finished half of work
2018-12-03 20:20:55 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage3’s is over,end
从结果看出CountDownLatch可以让线程在某一阶段受它限制,一个线程执行必须依赖CountDownLatch管理的线程的执行完毕才行。
而Join则没有这种功能,它必须让子线程执行完毕,才能让接下来的程序执行。但相对的,join代码写起来也相对简洁,明了。
四、最后,突然想到用CountDownLatch实现类似CyclicBarrier的功能,就是让所有任务都执行完,才进行下一阶段。类似一群羊在跑时,设置一个栅栏,等所有羊都到齐才开栅栏一样。
CountDownLatchThreeStage类
CountDownLatchThreeStage
package CountDownLatchAndJoin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchThreeStage extends Thread{
final Logger logger = LoggerFactory.getLogger(CountDownLatchSimple.class);
private CountDownLatch countDownLatch1;
private CountDownLatch countDownLatch2;
String name;
CountDownLatchThreeStage(String _name, CountDownLatch _countDownLatch1,CountDownLatch _countDownLatch2) {
name = _name;
countDownLatch1=_countDownLatch1;
countDownLatch2=_countDownLatch2;
}
@Override
public void run() {
try {
logger.info("{}'s stage1...",name);
Thread.sleep(2000);
countDownLatch1.countDown();
logger.info("{}'s stage2...",name);
Thread.sleep(2000);
countDownLatch2.countDown();
Thread.sleep(1000);
logger.info("{}'s stage3...",name);
}catch (InterruptedException e) {
logger.info("{}",name,e);
}
}
}
Test类
Test
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CountDownLatch;
public class Test {
final static Logger logger = LoggerFactory.getLogger(Main.class);
public void CountDownLatchThreeTasksStage() {
//CountDownLatch 多任务同时进入下一阶段,很low,要用Cyclicbarrier
CountDownLatch countDownLatch1 = new CountDownLatch(2);
CountDownLatch countDownLatch2 = new CountDownLatch(2);
CountDownLatchThreeStage countDownLatchStage1 = new CountDownLatchThreeStage("countDownLatchStage1",countDownLatch1,countDownLatch2);
CountDownLatchThreeStage countDownLatchStage2 = new CountDownLatchThreeStage("countDownLatchStage2",countDownLatch1,countDownLatch2);
countDownLatchStage1.start();
countDownLatchStage2.start();
try {
countDownLatch1.await();
countDownLatch2.await();
}catch (InterruptedException e) {
logger.error("countDownLatch.await,",e);
}
}
}
结果
2018-12-03 20:41:01 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage2’s stage1…
2018-12-03 20:41:01 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage1’s stage1…
2018-12-03 20:41:03 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage1’s stage2…
2018-12-03 20:41:03 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage2’s stage2…
2018-12-03 20:41:06 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage1’s stage3…
2018-12-03 20:41:06 INFO [CountDownLatchAndJoin.CountDownLatchSimple] countDownLatchStage2’s stage3…
当然,这里只是举例。在实用中还是要用CyclicBarrier来让所有任务完成才进入下一阶段。