1.CyclicBarrier(屏障)
CyclicBarrier类是通过设置屏障点来管理同步的,当所有参与的线程都到达指定屏障的时候,那么参与的所有线程就会全部 积蓄运行,具体测试代码如下:
public class CyclicBarrierTest {
// 定义一个循环屏障
private CyclicBarrier cyclicBarrier;
// 构造函数
//count为参与执行的线程数
//rn为所有线程到达屏障后需要做的行为
public CyclicBarrierTest(int count, Runnable rn) {
this.cyclicBarrier = new CyclicBarrier(count, rn);
}
public void sayHello(String name, int time) {
System.out.println("开始执行:" + name);
try {
Thread.sleep(time);
this.cyclicBarrier.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("结束执行:" + name);
}
public static void main(String[] args) {
final CyclicBarrierTest cbt = new CyclicBarrierTest(3, new Runnable() {
@Override
public void run() {
System.out.println("执行数量的线程完成后执行");
}
});
// 创建三个测试线程
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
cbt.sayHello("T1", 500);
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
cbt.sayHello("T2", 1000);
}
});
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
cbt.sayHello("T3", 2000);
}
});
//启动三个线程
t1.start();
t2.start();
t3.start();
}
}
上述代码的运行结果,应该是:
开始执行:T1
开始执行:T2
开始执行:T3
执行数量的线程完成后执行
结束执行:T1
结束执行:T2
结束执行:T3
2.CountDownLatch(计数)
CountDownLatch类是通过线程计数来实现同步的,也就是有一个计数器,在计数器未到0之前所有相关线程在指定位置都需要阻 塞,直到计数器为0的时候,所有相关线程停止阻塞,继续向下执行。需要注意的是,该同步器不能被复用,并且可以由外部事件触发。
public class CountDownLatchTest {
private CountDownLatch countDownLatch = null;
//构造函数,创建倒计时同步器
//count为倒计时数
public CountDownLatchTest(int count){
this.countDownLatch = new CountDownLatch(count);
}
//递减计数器
public void countDown(){
this.countDownLatch.countDown();
System.out.println("count:" + this.countDownLatch.getCount());
}
public void sayHello(String name, int time) {
System.out.println("开始执行:" + name);
try {
Thread.sleep(time);
this.countDownLatch.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("结束执行:" + name);
}
public static void main(String[] args) throws InterruptedException {
final CountDownLatchTest cdl = new CountDownLatchTest(3);
// 创建三个测试线程
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
cdl.sayHello("T1", 50);
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
cdl.sayHello("T2", 50);
}
});
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
cdl.sayHello("T3", 50);
}
});
//启动测试线程
t1.start();
t2.start();
t3.start();
Thread.sleep(2000);
//逐步递减
cdl.countDown();
Thread.sleep(1000);
cdl.countDown();
Thread.sleep(1000);
cdl.countDown();
Thread.sleep(1000);
}
}
上述代码由于线程运行的不确定性,每次的运行结果都不一样,但原则不变,例如:
开始执行:T1
开始执行:T2
开始执行:T3
count:2
count:1
count:0
结束执行:T2
结束执行:T3
结束执行:T1
3.Exchanger(交换)
Exchanger类用于不同线程间交换数据,并且交换过程是线程安全的,通过设置一个同步点来实现,具体代码如下:
public class ExchangerTest {
private Exchanger<String> exchanger;
public ExchangerTest(){
this.exchanger = new Exchanger<String>();
}
public void method1(String name){
System.out.println("执行Mehtod1");
//Thread.sleep(1000);\
String ss = name + "发送数据:123123" ;
try {
ss = this.exchanger.exchange(ss);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("结束Mehtod1");
}
public void method2(String name){
System.out.println("执行Mehtod2");
String ss = "123";
try {
ss = this.exchanger.exchange(ss);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Mehotd2收到:" + ss);
System.out.println("结束Mehtod2");
}
public static void main(String[] args) {
final ExchangerTest et = new ExchangerTest();
// 创建三个测试线程
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
et.method1("T1");
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
et.method2("T2");
}
});
//启动测试线程
t2.start();
t1.start();
}
}
上述代码的运行结果,应该是:
执行Mehtod2
执行Mehtod1
结束Mehtod1
Mehotd2收到:T1发送数据:123123
结束Mehtod2
4.SynchronousQueue(同步队列)
该同步器是阻塞队列的一种,虽然称之为队列,但是该“队列”没有长度。使用该队列的规则是:没有存不允许取,没有取不允许存。该队列的方法很多,但一般使用较多的是put和take方法,因为这两个方法实现了阻塞方式的存取,代码如下:
public class SynchronousQueueTest {
private SynchronousQueue<String> synchronousQueue;
public SynchronousQueueTest(){
//构造函数内的参数表示是否采取公平策略
//即优先照顾等待时间比较长的线程
//使用公平策略会影响性能
this.synchronousQueue = new SynchronousQueue<String>(false);
}
public void put(String data){
try {
System.out.println("等待放入:" + data);
this.synchronousQueue.put(data);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String take(){
String data = null;
try {
data = this.synchronousQueue.take();
System.out.println("提取了:" + data);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return data;
}
public static void main(String[] args) {
final SynchronousQueueTest sqt = new SynchronousQueueTest();
// 创建三个测试线程
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
sqt.put("111111");
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sqt.put("222222");
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
sqt.take();
sqt.take();
}
});
//启动测试线程
t1.start();
t2.start();
}
}
上述代码的运行结果,应该是:
等待放入:111111
提取了:111111
等待放入:222222
提取了:222222
5.Semaphore(信号量)
Semaphore类通过类似许可证的方式对同步进行管理,简单的来说,许可证的数目是一定的,想要访问,必须要获得许可证,若许可证已经用完,那么必须等待其他占用许可证的线程归还许可证后,方可得到许可从而继续执行。具体代码如下:
public class SemaphoreTest {
private Semaphore semaphore;
//构造函数用于创建一个信号量同步器
//count为许可个数
//fair表示是否采用公平策略
public SemaphoreTest(int count,boolean fair){
this.semaphore = new Semaphore(count,fair);
}
public void sayHello(String name){
try {
this.semaphore.acquire();
System.out.println(name + "得到许可");
Thread.sleep(5000);
this.semaphore.release();
System.out.println(name + "释放许可");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
final SemaphoreTest st = new SemaphoreTest(3,false);
// 创建测试线程
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
st.sayHello("T1");
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
st.sayHello("T2");
}
});
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
st.sayHello("T3");
}
});
Thread t4 = new Thread(new Runnable() {
@Override
public void run() {
st.sayHello("T4");
}
});
Thread t5 = new Thread(new Runnable() {
@Override
public void run() {
st.sayHello("T5");
}
});
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
上述代码由于线程运行的不确定性,每次的运行结果都不一样,但原则不变,例如:
T1得到许可
T2得到许可
T4得到许可
T2释放许可
T4释放许可
T3得到许可
T1释放许可
T5得到许可
T3释放许可
T5释放许可