并发编程(三)并发工具类

 

1.CountDownLatchCyclicBarrier

CountDownLatch是一个同步的辅助类,允许一个或多个线程,等待其他一组线程完成操作,再继续执行。

CyclicBarrier是一个同步的辅助类,允许一组线程相互之间等待,达到一个共同点,再继续执行。

他们都是:Synchronization aid,我把它翻译成同步辅助器,既然是辅助工具,怎么使用啊?哪些场景使用啊?

CyclicBarrier和CountDownLatch都位于java.util.concurrent 这个包下

CountDownLatch

CyclicBarrier

减计数方式

加计数方式

计算为0时释放所有等待的线程

计数达到指定值时释放所有等待线程

计数为0时,无法重置

计数达到指定值时,计数置为0重新开始

调用countDown()方法计数减一,调用await()方法只进行阻塞,对计数没任何影响

调用await()方法计数加1,若加1后的值不等于构造方法的值,则线程阻塞

不可重复利用

可重复利用


个人理解:CountDownLatch:我把他理解成倒计时锁:倒计时完成开始执行下一个任务

场景还原:一年级期末考试要开始了,监考老师发下去试卷,然后坐在讲台旁边玩着手机等待着学生答题,有的学生提前交了试卷,并约起打球了,等到最后一个学生交卷了,老师开始整理试卷,贴封条,下班,陪老婆孩子去了。

补充场景:我们在玩LOL英雄联盟时会出现十个人不同加载状态,但是最后一个人由于各种原因始终加载不了100%,于是游戏系统自动等待所有玩家的状态都准备好,才展现游戏画面。

个人理解:CyclicBarrier:可看成是个障碍,所有的线程必须到齐后才能一起通过这个障碍

场景还原:以前公司组织户外拓展活动,帮助团队建设,其中最重要一个项目就是全体员工(包括女同事,BOSS)在完成其他项目时,到达一个高达四米的高墙没有任何抓点,要求所有人,一个不能少的越过高墙,才能继续进行其他项目。

1.countDownlatch

public class countDownlatchTest implements Runnable{

private int id;

private CountDownLatch latch;

public countDownlatchTest(int id,CountDownLatch latch){

this.id = id;

this.latch = latch;

}

 
@Override

public void run() {

synchronized (this){

latch.countDown();//计数减一

System.out.println("线程组任务"+id+"结束,其他任务继续");

}

}


public static void main(String[] args) throws InterruptedException {

CountDownLatch countDownLatch =new CountDownLatch(5);

for (int a=0;a<5;a++){

Thread thread=new Thread(new countDownlatchTest(a,countDownLatch));

thread.start();

}

countDownLatch.await();//等待全部执行完成才执行之后的代码

System.out.println("线程执行结束。。。。");
 
}

}

 

1.CyclicBarrier

/**

* CyclicBarrier:可看成是个障碍,所有的线程必须到齐后才能一起通过这个障碍

*/

public class CyclicBarrierTest {

public static void main(String[] args) {

int N = 4;

CyclicBarrier barrier = new CyclicBarrier(N);

for(int i=0;i<N;i++)

new Writer(barrier).start();

}

static class Writer extends Thread{

private CyclicBarrier cyclicBarrier;

public Writer(CyclicBarrier cyclicBarrier) {

this.cyclicBarrier = cyclicBarrier;

}

 

@Override

public void run() {

 

System.out.println("线程"+Thread.currentThread().getName()+"正在写入数据...");

try {

Thread.sleep(5000); //以睡眠来模拟写入数据操作

System.out.println("线程"+Thread.currentThread().getName()+"写入数据完毕,等待其他线程写入完毕");

cyclicBarrier.await();//等待所有线程都完成才能执行以后的代码(同时放出多个线程万箭齐发)

} catch (InterruptedException e) {

e.printStackTrace();

}catch(BrokenBarrierException e){

e.printStackTrace();

}

System.out.println("线程"+Thread.currentThread().getName()+"所有线程写入完毕,继续处理其他任务...");

}

}

}

2. 控制并发线程数的Semaphore

Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。

应用:Semaphore可以用于做流量控制,特别是公用资源有限的应用场景,比如数据库连接。假如有一个需求,要读取几万个文件的数据,因为都是IO密集型任务,我们可以启动几十个线程并发地读取,但是如果读到内存后,还需要存储到数据库中,而数据库的连接数只有10个,这时我们必须控制只有10个线程同时获取数据库连接保存数据,否则会报错无法获取数据库连接。这个时候,就可以使用Semaphore来做流量控制,

public class SemaphoreTest {
    private static final int THREAD_COUNT = 30;
    private static ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_COUNT);
    private static Semaphore s = new Semaphore(10);// 每次只有10个线程可以访问
    public static void main(String[] args) {
        for (int i = 0; i< THREAD_COUNT; i++) {
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        s.acquire();//获取一个许可证(
                        System.out.println("save data");
                        s.release();//归还许可证。
                    } catch (InterruptedException e) {
                    }
                }
            });
        }
        threadPool.shutdown();
    }
}

 


2.   线程间交换数据的Exchanger

Exchanger(交换者)是一个用于线程间协作的工具类。Exchanger用于进行线程间的数据交换。它提供一个同步点,在这个同步点,两个线程可以交换彼此的数据。这两个线程通过 exchange方法交换数据,如果第一个线程先执行exchange()方法,它会一直等待第二个线程也执行exchange方法,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方。


猜你喜欢

转载自blog.csdn.net/zpoison/article/details/80942026