线程同步辅助类
Semaphore
Semaphore(信号量)是一种计数器,用来保护一个或者多个共享资源的访问
Semaphore接收一个int类型的整数,表示可以获取共享资源访问的次数
如:Semaphore semaphore = new Semaphore(3);
当调用semaphore.acquire()方法,信号量减去1,当信号量为0的时候,访问的线程进入等待状态
示例代码:
package javalearn.thread.helper;
import java.util.concurrent.Semaphore;
public class SemaphoreTest {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
Thread t1 = new Thread(new Print(semaphore));
Thread t2 = new Thread(new Print(semaphore));
Thread t3 = new Thread(new Print(semaphore));
Thread t4 = new Thread(new Print(semaphore));
t1.start();
t2.start();
t3.start();
//等待前3个线程任意一个释放才会执行
t4.start();
}
}
class Print implements Runnable {
private Semaphore semaphore;
public Print(Semaphore semaphore) {
this.semaphore = semaphore;
}
@Override
public void run() {
print();
}
private void print() {
try {
semaphore.acquire();
System.out.println("打印....需要3s");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
}
Semaphore还有其他的两个acquire()方法
acquireUninterruptibly(): 它其实就是acquire()方法。当信号量的内部计数器为0的时候,信号量会阻塞线程直到其被释放。线程在被堵塞的这段时间中,可能会被中断,从而导致acquire()方法抛出InterruptedException异常。而acquireUninterruptibly会忽略线程的中断并且不会抛出任何异常
**tryAcquire()😗*这个方法试图获得信号量,能获得到就返回true,否则返回false,避免线程某种情况下一直堵塞。
Semapore第二个参数支持设置是否是公平模式
CountDownLatch
CountDownLatch支持等待多个并发事件的完成,这个类使用一个整数进行初始化,这个整数就是线程要等待完成的操作的数目。当一个线程要等待某些操作先执行完时,需要调用await()方法,这个方法让线程进入休眠直到等待的所有操作都完成。当某一个操作完成后,它将调用countDown()方法将CountDownLatch类内部计数器减1,当计数器变成0的时候,它将调用所有await()方法而进入休眠的线程
示例代码:
package javastudy.thread_study.helper;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchTest {
public static void main(String[] args) {
/**
* 三个打印都完成,提示打印完成
*/
CountDownLatch countDownLatch = new CountDownLatch(3);
Thread done = new Thread(new Done(countDownLatch));
done.start();
Thread t1 = new Thread(new Print1(countDownLatch));
Thread t2 = new Thread(new Print1(countDownLatch));
Thread t3 = new Thread(new Print1(countDownLatch));
t1.start();
t2.start();
t3.start();
}
}
class Print1 implements Runnable{
private CountDownLatch countDownLatch;
public Print1(CountDownLatch countDownLatch){
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName() + "打印3s....");
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Done implements Runnable{
private CountDownLatch countDownLatch;
public Done(CountDownLatch countDownLatch){
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("打印任务全部完成");
}
}
CyclicBarrier
CyclicBarrier在集合点同步,它使用一个整数进行初始化,这个数就是线程等待完成的操作数量,它于CountDownLatch类似,但是也有一些区别
1.CountDownLatch是有一个线程,等待其他线程操作完成
2.CyclicBarrier是互相等待最后一个操作完成,同时支持传入一个Runnable进行到达集合点之后的处理
示例代码:
package javastudy.thread_study.helper;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierTest {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(3, new Runnable() {
@Override
public void run() {
System.out.println("人数全到,会议开始~~~");
}
});
Thread t1 = new Thread(new Meeting(cyclicBarrier));
Thread t2 = new Thread(new Meeting(cyclicBarrier));
Thread t3 = new Thread(new Meeting(cyclicBarrier));
t1.start();
t2.start();
t3.start();
}
}
class Meeting implements Runnable{
private CyclicBarrier cyclicBarrier;
public Meeting(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
try {
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName() + "已到");
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
Phaser
Phaser又称“阶段器”,用来解决控制多个线程分阶段共同完成任务的情景问题。它与CountDownLatch和CyclicBarrier类似,都是等待一组线程完成工作后再执行下一步,协调线程的工作。但在CountDownLatch和CyclicBarrier中我们都不可以动态的配置parties,而Phaser可以动态注册需要协调的线程,相比CountDownLatch和CyclicBarrier就会变得更加灵活。
示例代码:
package javastudy.thread_study.helper;
import java.util.Random;
import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;
/**
* 书上的小例子,用婚礼流程比较形象的演示了phaser的使用。
*
* Phaser 是一个类,继承这个类重写onAdvance(int phase, int registeredParties)
* 参数:两个参数分别是第几个阶段和到达这个阶段的线程数。
* 返回值:返回ture表示这个phaser结束了,因此只有最后一个阶段返回ture,其他阶段返回false。
* phase.bulkRegister(7);//注册总线程数。
*
*/
public class PhaserTest {
public static void main(String[] args) {
Phaser phaser = new MyPhaser();
// 7人参加婚礼
phaser.bulkRegister(7);
// 5个参加婚礼的客人
for (int i = 0; i < 5; i++) {
new Thread(new Person("P" + i, phaser)).start();
}
// 新郎和新娘
new Thread(new Person("新郎", phaser)).start();
new Thread(new Person("新娘", phaser)).start();
}
}
class Person implements Runnable {
private String name;
private Phaser phaser;
public Person(String name, Phaser phaser) {
this.name = name;
this.phaser = phaser;
}
public void arrived() {
try {
TimeUnit.SECONDS.sleep(3);
System.out.printf("%s is arrived! \n", name);
phaser.arriveAndAwaitAdvance();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void eat() {
try {
TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));
System.out.printf("%s is eated! \n", name);
phaser.arriveAndAwaitAdvance();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void leave() {
try {
TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));
System.out.printf("%s is leave! \n", name);
phaser.arriveAndAwaitAdvance();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void xx() {
try {
if (name.equals("新郎") || name.equals("新娘")) {
TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));
System.out.printf("%s is xx! \n", name);
phaser.arriveAndAwaitAdvance();
} else {
// 客人不参与XX 到达这个阶段就直接撤销。
phaser.arriveAndDeregister();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void run() {
arrived();
eat();
leave();
xx();
}
}
class MyPhaser extends Phaser {
@Override
protected boolean onAdvance(int phase, int registeredParties) {
switch (phase){
case 0:{
System.out.println("所有人到齐了,人数为:"+registeredParties);
return false;
}
case 1:{
System.out.println("所有人开始吃饭 !!人数为:"+registeredParties);
return false;
}
case 2:{
System.out.println("所有人吃完了,离席!!!人数为:"+registeredParties);
return false;
}
case 3:{
System.out.println("xx的人数为:"+registeredParties);
return true;
}
default:{
return true;
}
}
}
}
Exchanger
Exchanger允许在两个线程之间定义同步点,当两个线程都到达同步点时,他们交换数据结构,当某一个线程先到达exchange方法,它会等待另外一个线程调用exchange,然后进行数据交互。
示例代码:
package javastudy.thread_study.helper;
import java.util.concurrent.Exchanger;
import java.util.concurrent.TimeUnit;
public class ExchangerTest {
public static void main(String[] args) {
Exchanger<String> exchanger = new Exchanger<>();
new Thread(new A(exchanger)).start();
new Thread(new B(exchanger)).start();
}
}
class A implements Runnable{
private Exchanger<String> exchanger;
public A(Exchanger<String> exchanger){
this.exchanger = exchanger;
}
@Override
public void run() {
try {
String data = exchanger.exchange("A");
System.out.println("获取到线程B的数据" + data);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class B implements Runnable{
private Exchanger<String> exchanger;
public B(Exchanger<String> exchanger){
this.exchanger = exchanger;
}
@Override
public void run() {
try {
//让线程A等待3s在交换数据
TimeUnit.SECONDS.sleep(3);
String data = exchanger.exchange("B");
System.out.println("获取到线程A的数据" + data);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
本文如有任何问题,请留言指教,以免误导他人