您的位置:首页 > 其它

Cyclicbarrier和Countdownlatch对比和使用

2018-03-03 16:28 465 查看

CountDownLatch

包名: java.util.concurrent

用途:等待其他线程执行完毕后执行

主要方法:

构造器

/**
* Constructs a {@code CountDownLatch} initialized with the given count.
*
* @param count the number of times {@link #countDown} must be invoked
*        before threads can pass through {@link #await}
* @throws IllegalArgumentException if {@code count} is negative
*/
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}

线程等待 可以设置超时时间

public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}

计数器减1 每个线程执行完调用一次方法,直到count的值为0

public void countDown() {
sync.releaseShared(1);
}

使用demo

自己实现一个Runnable,传入CountDownLatch参数

/**
* 描述:
* 使用countdownlatch
*
* @author Kipeng Huang
* @create 2018-03-03 下午1:28
*/
public class CountRunnable implements Runnable {
private CountDownLatch countDownLatch;

public CountRunnable(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}

/**
* countDownLatch.countDown();  放在finally中执行
*/
@Override
public void run() {
try {
//打印线程名称
System.out.println(Thread.currentThread().getName());
System.out.println("开始处理数据...");
Thread.sleep(3000L);
System.out.println("数据处理完毕...");

} catch (InterruptedException e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();
}

}
}


测试main方法

/**
* 描述:
*
* @author Kipeng Huang
* @create 2018-03-03 下午1:32
*/
public class TestCountDownLatch {

public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(20);
//可以定义线程名称规则
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("demo-pool-%d").build();
//使用阿里Java规范自己创建线程池
ExecutorService threadPool = new ThreadPoolExecutor(4,
20,
1000L,
TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(1024),
namedThreadFactory,
new ThreadPoolExecutor.AbortPolicy());
for (int i = 0; i < 20; i++) {
threadPool.execute(new CountRunnable(countDownLatch));
}
countDownLatch.await();
System.out.println("全部数据处理完毕");
threadPool.shutdown();
}
}


执行结果

demo-pool-0
开始处理数据...
demo-pool-1
开始处理数据...
demo-pool-2
开始处理数据...
demo-pool-3
开始处理数据...
数据处理完毕...
数据处理完毕...
demo-pool-1
demo-pool-0
开始处理数据...
开始处理数据...
数据处理完毕...
demo-pool-2
开始处理数据...
数据处理完毕...
demo-pool-3
开始处理数据...
数据处理完毕...
数据处理完毕...
demo-pool-0
开始处理数据...
demo-pool-1
开始处理数据...
数据处理完毕...
demo-pool-2
开始处理数据...
数据处理完毕...
demo-pool-3
开始处理数据...
数据处理完毕...
数据处理完毕...
demo-pool-0
开始处理数据...
demo-pool-1
开始处理数据...
数据处理完毕...
demo-pool-2
开始处理数据...
数据处理完毕...
demo-pool-3
开始处理数据...
数据处理完毕...
demo-pool-0
开始处理数据...
数据处理完毕...
demo-pool-1
开始处理数据...
数据处理完毕...
demo-pool-2
开始处理数据...
数据处理完毕...
demo-pool-3
开始处理数据...
数据处理完毕...
数据处理完毕...
数据处理完毕...
数据处理完毕...
全部数据处理完毕

Process finished with exit code 0

从执行结果可以看出,主线程一直阻塞,知道count为0的时候执行

CyclicBarrier

包名: java.util.concurrent

用途: 通过它可以实现让一组线程等待至某个状态之后全部同时执行

主要的两个构造方法

/**
* @param parties 表示有多少线程阻塞在这里等待
* @param barrierAction 满足条件后执行这个任务
*/
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}

/**
* Creates a new {@code CyclicBarrier} that will trip when the
* given number of parties (threads) are waiting upon it, and
* does not perform a predefined action when the barrier is tripped.
*
* @param parties 表示有多少线程阻塞在这里等待
* @throws IllegalArgumentException if {@code parties} is less than 1
*/
public CyclicBarrier(int parties) {
this(parties, null);
}

使用demo

/**
* 描述:
*
* @author Kipeng Huang
* @create 2018-03-03 下午2:10
*/
public class CycleBarrierRunnable implements Runnable {
private CyclicBarrier cyclicBarrier;

public CycleBarrierRunnable(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}

@Override
public void run() {
System.out.println("当前线程名:" + Thread.currentThread().getName());
try {
Thread.sleep(2000);
cyclicBarrier.await();
System.out.println("线程" + Thread.currentThread().getName() + "执行完毕");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}

}
}

/**
* 描述:
*
* @author Kipeng Huang
* @create 2018-03-03 下午2:21
*/
public class BarrierTest {

public static void main(String[] args) {
ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat("demo-pool-%d")
.build();
ExecutorService threadPool = new ThreadPoolExecutor(20,
20,
2000L,
TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(1024),
threadFactory,
new ThreadPoolExecutor.AbortPolicy());

CyclicBarrier cyclicBarrier = new CyclicBarrier(20);

for (int i = 0; i < 20; i++) {
threadPool.execute(new CycleBarrierRunnable(cyclicBarrier));
}
cyclicBarrier.reset();
System.out.println("主线程程序执行");
threadPool.shutdown();

}
}

当前线程名:demo-pool-0
当前线程名:demo-pool-1
当前线程名:demo-pool-2
当前线程名:demo-pool-3
当前线程名:demo-pool-4
当前线程名:demo-pool-5
当前线程名:demo-pool-6
当前线程名:demo-pool-7
当前线程名:demo-pool-8
当前线程名:demo-pool-9
当前线程名:demo-pool-10
当前线程名:demo-pool-11
当前线程名:demo-pool-12
当前线程名:demo-pool-13
当前线程名:demo-pool-14
当前线程名:demo-pool-15
当前线程名:demo-pool-16
当前线程名:demo-pool-17
当前线程名:demo-pool-18
主线程程序执行
当前线程名:demo-pool-19
线程demo-pool-19执行完毕
线程demo-pool-1执行完毕
线程demo-pool-3执行完毕
线程demo-pool-4执行完毕
线程demo-pool-8执行完毕
线程demo-pool-0执行完毕
线程demo-pool-11执行完毕
线程demo-pool-10执行完毕
线程demo-pool-9执行完毕
线程demo-pool-6执行完毕
线程demo-pool-7执行完毕
线程demo-pool-5执行完毕
线程demo-pool-2执行完毕
线程demo-pool-17执行完毕
线程demo-pool-18执行完毕
线程demo-pool-16执行完毕
线程demo-pool-15执行完毕
线程demo-pool-13执行完毕
线程demo-pool-14执行完毕
线程demo-pool-12执行完毕

Process finished with exit code 0

注意事项

如果线程池核心线程数小于CyclicBarrier的数量,则一直阻塞。无法执行

ExecutorService threadPool = new ThreadPoolExecutor(3,
20,
2000L,
TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(1024),
threadFactory,
new ThreadPoolExecutor.AbortPolicy());

执行结果

当前线程名:demo-pool-0
当前线程名:demo-pool-1
当前线程名:demo-pool-2
主线程程序执行

Cyclicbarrier和Countdownlatch的区别

|CountDownLatch|CyclicBarrier|
| -- | -- |
| 减基数方式 | 加基数方式 |
| 计数为0的时候释放所有等待的线程 | 基数达到指定值时释放所有等待线程 |
| 基数为0时,无法重置,只能使用一次 | 基数达到指定值时,计数置为0,重新开始 |
| 调用countDown方法减一,await方法阻塞 | 调用await方法 |
| 不可重复使用 | 可重复使用 |
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息