高并发和多线程(三)——CountDownLatch,CyclicBarrier,Phaser,ReadWriteLock,Exchanger,LockSupport
写一下多线程下面经常用的方法,理解用好这些方法,能解决很多问题
CountDownLatch
private static void useContDownLatch(){
Thread[] t1 = new Thread[100];
CountDownLatch countdown = new CountDownLatch(t1.length);
for (int i = 0; i <t1.length ; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"-开始计算");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-计算完成");
countdown.countDown();
}).start();
}
try {
countdown.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("countdown end ----");
}
第一个是开始信号,在发出执行命令前,阻止线程开始执行。
第二个是完成信号,直到所有线程执行完毕,主线程再开始执行。
使用场景:
CountDownLatch 就是一个信号器,在多线程情况下每次执行contdown()方法就会减1,一直减到0为止,我在实际使用场景中是在多表刷数据工具,使用时启用一个线程池,声明一个count为2000的信号器,一个线程跑完一张表countdown一次,循环跑完2000张表然后await,
数据清洗完毕更新记录表,记录表中间如果有异常会记录在哪张表出的异常,可以下次直接从记录表拿到当前表开始清洗数据。
CyclicBarrier
private static void useCyclicBarrier(){
CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
@Override
public void run() {
System.out.println("满人,我们开始干掉他们");
}
});
for (int i = 0; i <100 ; i++) {
new Thread(()->{
try {
System.out.println("我来加入王者战队了");
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
多个线程互相等待,直到到达同一个同步点,再继续一起执行。CyclicBarrier适用于多个线程有固定的多步需要执行,线程间互相等待,当都执行完了,在一起执行下一步。
以上的例子利用了CyclicBarrier提供的一个更高级的构造函数CyclicBarrier(int parties, Runnable barrierAction),用于在线程到达屏障时,优先执行barrierAction,方便处理更复杂的业务场景。
使用场景:
假设要进行一个大量的计算,得到最终的值。如果使用单线程会很慢,使用多线程,又不知道最终什么时候把结果合并,这个使用 CyclicBarrier 就很有用了
Phaser
private static void userPhaser(){
MarriagePhaser phaser = new MarriagePhaser();
phaser.bulkRegister(5);
for (int i = 0; i <5 ; i++) {
final int nameIndex = i;
new Thread(()->{
Person p = new Person("person"+nameIndex);
p.arrive();
phaser.arriveAndAwaitAdvance();
p.eat();
phaser.arriveAndAwaitAdvance();
p.leave();
phaser.arriveAndAwaitAdvance();
}).start();
}
}
static class MarriagePhaser extends Phaser{
@Override
protected boolean onAdvance(int phase, int registeredParties) {
switch (phase){
case 0:
System.out.println("所有人都到齐了");
return false;
case 1:
System.out.println("可以开始吃了");
return false;
case 2:
System.out.println("所有人离开了!");
System.out.println("婚礼结束!");
return true;
default :
return true;
}
}
}
static class Person{
String name;
public Person(String name) {
this.name = name;
}
public void arrive() {
System.out.printf("%s 到达现场!\n", name);
}
public void eat() {
System.out.printf("%s 吃完!\n", name);
}
public void leave() {
System.out.printf("%s 离开!\n", name);
}
}
它支持任务在多个点都进行同步,支持动态调整注册任务的数量。当然你也可以使用CountDownLatch,但你必须创建多个CountDownLatch对象,每一阶段都需要一个CountDownLatch对象。
ReadWriteLock
private static void userReadWriteLock(){
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
Lock readlock = readWriteLock.readLock();
Lock writelock = readWriteLock.writeLock();
Runnable readR = ()-> read(readlock);
//Runnable writeR = ()->write(lock, new Random().nextInt());
Runnable writeR = ()->write(writelock);
for(int i=0; i<18; i++) new Thread(readR).start();
for(int i=0; i<2; i++) new Thread(writeR).start();
}
public static void read(Lock lock){
lock.lock();
try {
TimeUnit.SECONDS.sleep(1);
System.out.println("read over!");
//模拟读取操作
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public static void write(Lock lock){
lock.lock();
try {
TimeUnit.SECONDS.sleep(1);
System.out.println("write over!");
//模拟写操作
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}