java并发编程之三、协调

在现实世界,不仅仅只有分工,还有协作,当异步执行的任务到了一定的阶段之后,还需要跟其他异步任务进行同步,这样才能开始下一个阶段的任务,Java在异步任务之间的协调或者同步机制上也提供了很多手段。按照介绍的顺序,提供的协调的灵活度越来越高。

一、Join

join是Thread类型的一个方法,是一个简单的用来在同步的机制,如果在主线程中调用A线程的join方法,则主线程会阻塞在调用点上,等等A线程的执行结束。如果主线程需要和多个同步参与方进行同步操作,进行多个线程的join操作虽然是可以的,但毕竟不优美,下面的同步机制或许更好用。

二、Wait Notify NotifyAll

这三个方法都是Object类型的方法,每一个同步参与方都可以在获得同步对象锁的前提下,调用同步对象的wait方法进行等待,但wait方法会让渡出cpu的使用权并释放同步对象锁,而notify和notifyALL也都需要在获得同步对象锁的前期下调用,他们虽然都是唤醒某个调用了wait方法的同步参与方,但一般建议使用notifyAll,因为他是唤醒所有的等待同步参与方,然后大家再去争抢锁,而notify则只会唤醒某一个同步参与方。

总有人会问,为什么这三个方法是在Object类型中,而不是在Thread类型中,因为他的使用场景是在同步对象中,而同步对象是个普遍意义上的对象,显然就应该Object中。

三、CountDownLatch

CountDownLatch在有多个同步参与方的时候很好用,比如同样的场景,主线程中需要等待5个同步参与方,如果用join,一则代码不好看,二则在线程池中无法使用,这里就可以使用CountDownLatch来做同步,构建一个有5个参与方的CountDownLatch对象,在每个同步参与方完成自己的任务后,调用CountDownLatch对象的countDown方法,而在主线程中可以调用await方法来进行等待,一旦所有的5个参与方都调用了countDown方法,则主线程就可以继续同步后的工作。

四、CyclicBarrier

CyclicBarrier在用法上和CountDownLatch很相似,但他又有自己的几个特点:

  • 同步主体,不像CountDownLatch是用来同步主线程和参与线程,CyclicBarrier用来既可以用来同步主线程和参与线程,也可以用来进行参与线程之间的同步。比如做面包,有A线程生成面包粉,B线程生成黄油,C线程利用面包粉和黄油来生成面包,即需要将A和B与C同步,A和B之间最好也能同步,不然A或者B任意一方跑的太快也没意义。
  • 支持回调,A和B之间的同步,在CyclicBarrier中通过调用await方法来实现,当两个线程都调用了await方法,则他们可以开始生成下一份的面包粉和黄油,而A和B与C之间的同步在通过回调实现,需要在构建CyclicBarrier对象时,传入一个利用面包粉和黄油来生成面包的对象。
  • 循环使用,CountDownLatch对象在同步过程结束后就不能再使用,而CyclicBarrier则可以循环使用,像他的名字一样,做面包的过程可以一直继续下去。

五、Phaser

Phaser是在java 1.7中才引入的一个同步barrier,它非常的灵活好用。

  • 特点
    • 构造,可以使用无参和有参的构造函数,取决于在构造前期是否确定已知的同步参与方。
    • 参与,Phaser除了在构造的时候确定参与方,还可以动态参与,这个特点是CountDownLatch和CyclicBarrier都不具备的。
    • 循环,Phaser和cyclicBarrier一样,也可以循环使用,当一个阶段的同步完成后,可以参与下一个阶段的任务的同步。  
  • 使用
    • register,同步任务的多个参与方需要调用同一个phaser对象的register方法,让自己加入到同步中去。
    • arriveAndAwaitAdvance,参与方调用这个方法,表明已经做好自己的工作,开始阻塞等待其他同步参与方都到达,然后开始其他的工作。如果没有其他的工作,则可以直接调用arrive方法,表示自己已经到达,但不阻塞,即不等待其他同步参与方。
    • arriveAndDeregister,这个方法其实与上面的类似,也表示了做好了准备的意思,但是arriveAndAwaitAdvance表达了到达并阻塞,需要等候其他同步方,而arriveAndDeregister则很简单的表达了到达并取消注册,即这个同步参与方不参与同步后的工作。
posted @ 2020-01-15 10:30  boiledwater  阅读(237)  评论(0编辑  收藏  举报