呀?这就是锁(二)?
java常用锁
CountDownLatch(倒数计数器,门栓)
package AboutSysn;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo {
public static void main(String[] args) {
CountDownLatch cdl = new CountDownLatch(2); //添加两道栅栏,
for(int i = 0;i<5;i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"-----1");
if(cdl.getCount()>0) {
cdl.countDown(); //释放一层栅栏
}
try {
cdl.await(); //等待栅栏全部释放后,才可以继续执行
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-----2");
}).start();;
}
}
}
总结:
CountDownLatch 维护了一个int变量,当这个变量等于0是,所有等待这个变量的线程开始运行。等待的过程使用的是CAS,这个最后写到AQS时详说,现在只需要明白只要线程执行了 cdl.await,其背后的意义就是告诉这个线程你要等待 cdl 的 count 的值变成0。
CyclicBarrier(同步屏障)
package AboutSysn;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cb = new CyclicBarrier(2);
List<Thread> threads = new ArrayList<Thread>();
for(int i = 0;i<6;i++) {
Thread t = new Thread(()->{
System.out.println(Thread.currentThread().getName()+"到达");
try {
cb.await(); //等待其他线程到达
System.out.println(Thread.currentThread().getName()+"执行了");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
threads.add(t);
}
threads.forEach(o->{
o.start();
try {
Thread.sleep(1000);
System.out.println(o.getName()+"开始执行");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
}
}
//结果 这个结果还能证明指令重排序,优秀!!!!
Thread-0到达
Thread-0开始执行
Thread-1到达
Thread-1执行了
Thread-0执行了
Thread-1开始执行
Thread-2到达
Thread-2开始执行
Thread-3到达
Thread-3执行了
Thread-2执行了
Thread-3开始执行
Thread-4到达
Thread-4开始执行
Thread-5到达
Thread-5执行了
Thread-4执行了
Thread-5开始执行
总结:
我们可以使用CyclicBarrier使需要彼此配合的线程协同工作,例如ThreadA的计算需要ThreadB的部分结果就可以这样使用。相当于增强的CountDownLatch
Phaser
package AboutSysn;
import java.util.concurrent.Phaser;
public class PhaserDemo {
static Phaser p = new MyPhaser();
//看电影
static class MyPhaser extends Phaser{
protected boolean onAdvance(int phase, int registeredParties) {
System.out.println(phase+"--"+registeredParties);
switch (phase) {
case 0:
//这里进行所有线程都要执行的任务
System.out.println("所有人进场");
return false;
case 1:
System.out.println("观看电影");
return false;
case 2:
//这里执行只有管理员线程要做的任务
System.out.println("除管理员,其他人离场");
return true;
default:
return true;
}
}
}
public static void main(String[] args) {
p.bulkRegister(5); //p会拦截5个线程然后放行
Runnable r = new Runnable() {
void m1() {
System.out.println("m1");
p.arriveAndAwaitAdvance();
}
void m2() {
System.out.println("m2");
p.arriveAndAwaitAdvance();
}
void m3() {
System.out.println("m3");
String name = Thread.currentThread().getName();
if(!name.equals("Thread-4")) {
p.arriveAndDeregister(); //游客线程去掉
}else {
p.arriveAndAwaitAdvance(); //管理员线程保留
}
}
@Override
public void run() {
// TODO Auto-generated method stub
m1(); //第一次栅栏拦截,
m2(); //第二次栅栏拦截
m3(); //第三次栅栏拦截
}
};
for(int i=0;i<5;i++)
{
new Thread(r).start();;
}
}
}
//结果
m1
m1
m1
m1
m1
0--5
所有人进场
m2
m2
m2
m2
m2
1--5
观看电影
m3
m3
m3
m3
m3
2--1
除管理员,其他人离场
总结:
Phaser其本质和另外两种没有什么区别,相当于增强了CyclicBarrier,可以在过程中对拦截线程数量进行动态的调整,可以让一部分线程做一个特殊的任务。