编程语言
首页 > 编程语言> > Java并发编程基础03-高级线程同步机制

Java并发编程基础03-高级线程同步机制

作者:互联网

简介

3种基本的同步机制:

高级同步机制:

信号量机制

如果信号量内部的计数器的值大于0,那么信号量就递减计数器并允许线程访问。

如果计数器的值为0,信号量会让线程休眠,直到计数器的值大于0。

Java的Semaphore类提供了信号量机制。


操作:


使用信号量实现临界区来保护共享资源所要遵循的3个步骤:


可以一次性获取或者释放多个信号量:

acquire()、acquireUninterruptibly()、tryAcquire()以及release()方法,均有一个带有一个整型参数的版本。


Semaphore公平和非公平模式:

Semaphore类提供了重载的构造器,它允许传入第二个参数。

如果传入参数为false,则创建的Semaphore将工作在非公平模式下,这也是不传该参数时的默认模式;如果传入参数为true,则创建的Semaphore将工作在公平模式下。

倒计时机制

Java并发API提供了一个类CountDownLatch,它可以使多个线程等待直到一组操作完成。

当一个线程希望等待这些操作执行完成时,可以调用CountDownLatch对象的await(),这个方法会将调用线程休眠,直到所等待的操作全部结束。而当一个操作结束时,应该调用CountDownLatch对象的countDown()方法,该方法会将CountDownLatch对象内部的属性计数器的值减1,表示一个操作的完成。当CountDownLatch对象内部的计数器的值为0时,表示所有操作都完成了。这时,CountDownLatch对象将唤起所有因调用其await()方法而休眠的线程。


操作:


运行模式:

在创建CountDownLatch对象时,构造器的参数将用来初始化对象内部的计数器。每次调用countDown()方法时,CountDownLatch对象的计数器的值都减1。当计数器的值为0时,CountDownLatch对象唤醒全部因调用await()方法而休眠等待的线程。


CountDownLatch一次性特性:

其实例对象的同步作用是一次性的。正如之前所示,当CountDownLatch对象内部的计数器的值为0时,后续对其的调用将不会产生任何作用。

在指定状态点同步任务

CyclicBarrier运行机制:

CyclicBarrier类的构造器需要有一个整型参数,这个参数表示在指定点进行同步的线程个数。当需要同步的线程运行到指定点时,可以调用CyclicBarrier对象的await()方法,然后等待其他线程达到指定点。这个方法使调用线程休眠,等待其他线程的到达。当最后一个需要同步的线程到达并调用CyclicBarrier对象的await()方法时,所有在此等待的线程都会被唤醒并继续执行。

CyclicBarrier类定义了内部计数器,它对需要在同步状态点进行同步的线程数进行控制。每当一个线程执行到同步状态点时,它会通过调用await()通知CyclicBarrier对象有一个线程已达到同步状态点,这时CyclicBarrier对象将内部计数器的值减1,并将调用线程休眠,直到所有线程均达到同步状态点。


构造函数传入第二个参数Runnable:

CyclicBarrier对象会在所有同步线程到达指定点后,将Runnable对象当作一个线程对象来执行。


一些其他方法:

getNumberWaiting()方法:该方法会返回因调用await()而休眠等待的线程数;

getParties()方法:该方法返回CyclicBarrier对象同步的任务数。


CyclicBarrier可以重置,这是和CountDownLatch很不同的点:

CyclicBarrier类提供的reset()方法可以实现重置。当调用这个方法后,所有因调用await()方法而休眠等待的线程,将收到BrokenBarrierException异常。


CyclicBarrie损坏状态:

当多个线程因调用await() 方法而等待时,若其中一个被中断了,则此线程会收到Interrupted- Exception异常,而其他线程将收到BrokenBarrierException异常,并且CyclicBarrier对象会进入损坏状态。

CyclicBarrier类提供了isBroken()方法。如果CyclicBarrier对象处于损坏状态,则调用该方法将返回true;否则,将返回false。

运行阶段性并发任务

Phaser类提供了在每步结束时同步线程的机制,这使得只有当所有线程都完成第一步后,才会有线程开始执行第二步操作。

CyclicBarrier也可以完成类似的功能。


Phaser对象可以动态增加和减少同步的任务数量:

在初始化Phaser对象时,必须指明参与同步的任务数量,但是它可以动态地增加或者减少同步参与者。


操作:


与其他同步工具类不同,由Phaser休眠的线程不会响应中断,也不会抛出中断异常


arrive()方法:

该方法将通知Phaser类,一个参与者已经完成当前的阶段任务,并将继续执行,不等待该阶段的其他参与者。

一个值得思考的问题:arrive之后再次arriveAndAwaitAdvance()是等待下一阶段,还是这一阶段?

答:phaser的机制很简单,每有一个线程调用了arrive,phaser需要等待的线程就减1,有个线程连续调用arrive,他甚至可以用一个线程完成一个阶段所有需要调用的线程


动态调整Phaser中参与者数量:


强制终止Phaser:

Phaser类提供的forceTermination()方法可改变Phaser对象的状态,不论该对象注册了多少个同步参与者,该方法都会将Phaser对象置于终止状态。

当一个Phaser对象处于终止状态时,调用awaitAdvance()和arriveAndAwait- Advance()方法将立即返回一个负数(通常状态下,返回的是正数)。

阶段性并发任务的终止状态转变控制

Phaser类提供了方法onAdvance()【protected方法】,并在阶段转变时自动调用此方法。如果该方法返回为True,则phaser进入终止状态。

onAdvance()方法的默认实现为,如果Phaser上注册的参与者数量为0,则返回true,否则为false。


需要重写该方法,实现阶段转变控制:

该方法接收刚执行完成的阶段数(从0开始计数),它还接收一个代表参与者数量的参数。

两个并发任务间的数据交换

Exchanger工具类允许在两个线程间定义一个同步点,当两个线程到达该同步点时,它们能够交换内部的数据结构,使得第一个线程的数据结构传递给第二个线程,反之亦然。

注:Exchanger只能在两个线程间同步


构造方法:

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

运行机制:

与其他同步工具类一样,第一个调用exchange()方法的线程将会休眠,直到该方法由另一个线程调用。然后同时交换数据,类似于线程间的swap操作。

★CompletableFuture机制★

CompletableFuture实现了Future接口CompletionStage接口


3种使用CompletableFuture类的方法:


该节的案例非常经典,写得很好,值得总结与回顾


CompletableFuture类的静态方法allOf():

该方法接收变长的CompletableFuture对象作为参数,不会等待所有传入CompletableFuture完成,才返回,不会阻塞线程


“其他说明部分”也是很经典,值得总结

标签:03,Phaser,Java,对象,同步,调用,线程,方法
来源: https://www.cnblogs.com/doubest/p/15488826.html