JUC下线程同步类
2019-08-13 本文已影响0人
一只小星_
这些类为JUC包,他们都起到线程同步作用
Semaphore(信号量)
/**
* @className: SemaphoreExample1
* @description: 允许多个线程同时访问(syn,reentrantLock每次只允许访问一个)
* @author: wbr
* @date: 2019-08-13 13:25
*/
public class SemaphoreExample1 {
//请求的数量
private static final int threadCount = 50;
public static void main(String[] args) throws InterruptedException {
创建固定数量的线程池对象,如果数量少了会执行的很慢
ExecutorService threadPool = Executors.newFixedThreadPool(300);
一次只能执行的线程数量
final Semaphore semaphore = new Semaphore(20);
for (int i=0;i<threadCount;i++){
final int threadNum = i;
threadPool.execute(()->{
try {
获得一个许可,如果没有了,就阻塞。里面可以传参数一次性获取多个
semaphore.acquire();
test(threadNum);
释放一个许可,可能会唤醒一些阻塞的线程。释放也可以传参数。
semaphore.release();
}catch (InterruptedException e){
e.printStackTrace();
}
});
}
threadPool.shutdown();
System.out.println("finish");
}
* 除了acquire()和release(),另一个常用的是tryAcquire(),获取不到就返回false。
* Semaphore有两种模式:公平和非公平。
* 公平调用acquire的顺序就是获取许可的顺序,遵循AQS的FIFO。
* 非公平就是抢占式。
*
* Semaphore的构造方法只有两个,默认非公平,都要传入信号量的值:
* public Semaphore(int permits) {
* sync = new NonfairSync(permits);
* }
*
* public Semaphore(int permits, boolean fair) {
* sync = fair ? new FairSync(permits) : new NonfairSync(permits);
* }
public static void test(int threadNum) throws InterruptedException{
//模拟请求耗时操作
Thread.sleep(1000);
System.out.println("threadNum:"+threadNum);
//模拟请求耗时操作
Thread.sleep(1000);
}
}
在现实场景,Semaphore的实现,比如线程池,你创建的线程池的连接数是有限制的,里面就类似Semaphore实现。
源码深入:https://blog.csdn.net/qq_19431333/article/details/70212663
CountDownLatch (倒计时器)
这个类常常用于等待,等多个线程执行完毕,再让某个线程执行。
CountDownLatch的典型用法就是:
①某一线程在开始运行前等待n个线程执行完毕。将 CountDownLatch 的计数器初始化为n :new CountDownLatch(n),每当一个任务线程执行完毕,就将计数器减1 countdownlatch.countDown(),当计数器的值变为0时,在CountDownLatch上 await() 的线程就会被唤醒。一个典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行。
public class CountDownLatchExample1 {
//请求的数量
private static final int threadCount = 550;
public static void main(String[] args) throws InterruptedException{
ExecutorService executorService = Executors.newFixedThreadPool(300);
final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
for (int i=0;i<threadCount;i++){
final int threadNum = i;
executorService.execute(() ->{
try {
test(threadNum);
}catch (InterruptedException e){
e.printStackTrace();
}finally {
//表示一个请求已完成
countDownLatch.countDown();
}
});
}
//await之后的都要等待,等countDownLatch减到0,await之后的才能执行
countDownLatch.await();
executorService.shutdown();
}
public static void test(int threadCount) throws InterruptedException{
//模拟请求的耗时操作
Thread.sleep(1000);
System.out.println("threadCount:"+threadCount);
Thread.sleep(1000);
}
}
CountDownLatch是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当CountDownLatch使用完毕后,它不能再次被使用。
CyclicBarrier(循环栅栏)
CyclicBarrier 和 CountDownLatch 非常类似,它也可以实现线程间的技术等待,CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。

public class CyclicBarrierExample3 {
// 请求的数量
private static final int threadCount = 550;
// 需要同步的线程数量
private static final CyclicBarrier cyclicBarrier = new CyclicBarrier(5, () -> {
System.out.println("------当线程数达到之后,优先执行------");
});
public static void main(String[] args) throws InterruptedException {
// 创建线程池
ExecutorService threadPool = Executors.newFixedThreadPool(10);
for (int i = 0; i < threadCount; i++) {
final int threadNum = i;
Thread.sleep(1000);
threadPool.execute(() -> {
try {
test(threadNum);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
}
threadPool.shutdown();
}
public static void test(int threadnum) throws InterruptedException, BrokenBarrierException {
System.out.println("threadnum:" + threadnum + "is ready");
cyclicBarrier.await();
System.out.println("threadnum:" + threadnum + "is finish");
}
}