《Java并发编程的艺术》之同步工具

CountDownLatch

该类主要实现了:让一个线程等待其余线程完成后再执行的功能,比如Thread.join()java

该类的初始化须要一个整数值count,当每次调用CountDownLatch.countDown()时Count会递减。直到count降到0时,全部执行CountDownLatch.await()的方法都会返回。算法

初始化了一个共享变量latch,并赋予count为3数据库

CountDownLatch latch = new CountDownLatch(3);

建立一个任务,睡眠1秒伪装执行任务,最后执行countDownide

@Override
public void run() throw InterruptedException{
    System.out.println("执行任务...");
    Thread.sleep(1000);
    latch.countDown();
}

主线程里执行以下方法工具

// 调用3个线程执行上述的任务
...
latch.await();
System.out.println("执行结束")

当三个任务线程所有执行完latch.countDown()时,main线程就会从阻塞的await()中返回,最后输出"执行结束"。
注意:CountDownLatch 只能使用一次,下一次使用要从新建立一个。学习

CylicBarrier

该类和CountDownLatch有点相似,不过从名字就能够看出它是一个可循环使用 的类。它的功能主要是等待全部线程达到某个位置,而后统一执行。能够想象成出发旅游,你们都先到集合地等待,待全部人都到了,就能够出发了。线程

建立一个屏障code

CyclicBarrier barrier = new CyclicBarrier(4);

任务类,让先完成的任务进行等待,等待其余线程到达get

@Override
public void run() throw InterruptedException{
    System.out.println(Thread.currentThread.getName() + " -> 到达集合点");
    barrier.await();
    System.out.println(Thread.currentThread.getName() + "出发!")
}

睡5秒,不让主线程过早结束同步

// 建立4个线程执行上述的任务
...
Thread.sleep(5000);
System.out.println("执行结束")

注意,若是barrier在等待过程当中某个线程被中断了一次,那么整个barrier就须要从新来过。

Thread thread = new Thread(() -> {
    try {
        barrier.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (BrokenBarrierException e) {
        e.printStackTrace();
    }
});
thread.start();
thread.interrupt();
try{
    barrier.await();
}catch (Exception e){
    System.out.println("没法等待...");
}

当另起的线程被中断后,后续的barrier就没法使用了,会抛出BrokenBarrierException

Semaphore

该类被称做信号量,用于控制同一时间的线程执行数。想象下面一副场景:

-----------------
🚌     🚌 🚌 🚌↘---------------
🚌   🚌   🚌    🚌🚌  🚌🚌
   🚌    🚌  🚌↗---------------
-----------------

在窄路口里每次只能经过5辆车,5辆车经过后,后5辆车才能经过。Semaphore的做用就和它很相似,当有20条线程在执行IO密集型的任务,执行完后须要将处理结果存储到数据库中。若是数据库链接只有10条,那就要用semaphore去控制拿到数据库链接的线程数量。

Semaphore里没用过的方法:

  • hasQueuedThreads():是否有等待的线程
  • getQueueLength():返回正在等待获取许可证的线程数量

Exchanger

该类是一个用于线程间协做的工具类。Exchanger用于进行线程间的数据交换。它提供一个同步点,在这个通不见,两个线程能够交换彼此间的数据。这两个线程经过exchange方法交换数据:若是第一个线程执行exchange(),它会一直等待第二个线程exchange(),当两个线程达到同步点,这两个线程就能够交换线程。
虽然我不知道这个类有啥做用(ε=ε=ε=┏(゜ロ゜;)┛
可是书上说能够用于遗传算法、校对工做:

Exchanger<String> exchanger = new Exchanger<>();

new Thread(() -> {
    String dataOfAThread = Thread.currentThread().getName() + "-----A的数据";
    try {
        String resultOfBThread = exchanger.exchange(dataOfAThread);
        System.out.println(Thread.currentThread().getName() + "-------> " + resultOfBThread);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}).start();

new Thread(() -> {
    String dataOfBThread = Thread.currentThread().getName() + "-----B的数据";
    try {
        String resultOfAThread = exchanger.exchange(dataOfBThread);
        System.out.println(Thread.currentThread().getName() + "-------> " + resultOfAThread);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}).start();

最后输出:

Thread-1-------> Thread-0-----A的数据
Thread-0-------> Thread-1-----B的数据

总结

从新熟悉一下同步工具,学习到了CyclicBarrier被中断一次后,整个做废的点;学习到了Exchanger的适用场景

相关文章
相关标签/搜索