四者都是jdk1.5的新特性
一、CountDownLatch
举例:老师等学生到齐后上课
1、涉及线程:1个老师线程,多个学生线程。
2、多个学生线程共用一个new CountDownLatch()对象,当来了一个学生后,该学生(线程)就调用countDownLatch.countDown();
所以需要给学生线程的构造方法指定要使用的countDownLatch(且必须是同一个);
3、老师(主线程)调用countDownLatch.await()进行等待所有学生的到来(都到来后,才会继续执行老师线程)
自己写的代码
public class AboutCountDownLatchAndCyclicBarrier {
static class MyCountDownLatch implements Runnable{
private CountDownLatch countDownLatch;
public MyCountDownLatch(CountDownLatch countDownLatch){
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName() + "执行了一个countDownLatch");
countDownLatch.countDown();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
int sumStudent = 5;
CountDownLatch latch = new CountDownLatch(sumStudent);
for (int i = 0; i < sumStudent; i++) {
new Thread(new MyCountDownLatch(latch), String.valueOf(i)).start(); //所有学生线程都操纵同一个CountDownLatch对象
}
System.out.println("现在等待" + sumStudent + "个学生到齐");
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(sumStudent + "个学生都到齐了,老师开始上课");
}
}
二、CyclicBarrier
举例:几个员工翻墙,一堵墙大家都翻过了,才能翻下一堵墙。
1、涉及线程:多个员工。(相互牵制,等到大家都完成了,大家再一起去做下一件事)
2、多个人共用一个new CyclicBarrier(employeeSum),当一个员工翻过后,就调用cyclicBarrier.await(),等待其他员工翻过来;
所以需要给员工线程的构造方法指定要使用的cyclicBarrier(且必须是同一个);
3、主线程启动这些线程后,什么都不用干,因为这里不存在主线程等来员工翻过所有墙后需要干些什么。
public class CyclicBarrierTest {
private static class MyRunnable implements Runnable{
private CyclicBarrier barrier;
public MyRunnable(CyclicBarrier barrier){
this.barrier = barrier;
}
@Override
public void run() {
for(int i = 0; i < 3; i++) {
try {
Random rand = new Random();
int randomNum = rand.nextInt((3000 - 1000) + 1) + 1000;//产生1000到3000之间的随机整数
Thread.sleep(randomNum);
System.out.println(Thread.currentThread().getName() + ", 通过了第"+i+"个障碍物, 使用了 "+((double)randomNum/1000)+"s");
this.barrier.await();//(相互牵制,等到大家都完成了,大家再一起去做下一件事)
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(3);
for(int i = 0; i < barrier.getParties(); i++){
new Thread(new MyRunnable(barrier), "队友"+i).start();
}
System.out.println("main function is finished."); //主线程启动这些线程后,什么都不用干
}
}
三、Semaphore
semaphore.acquire();
semapore.release();
详见下面的Semaphore
小总结:
三者统一用法,都是
CountDownLatch latch = new CountDownLatch(几个);
CyclicBarrier barrier = new CyclicBarrier(几个);
Semaphore semaphore = new Semaphore(几个);
然后
for(int i = 0; i<几个; i++){
new Thread()
}
一、CountDownLatch(倒计时锁)-jdk1.5
在jdk1.5之前,使用join()来实现类似的功能;(学生线程join进来,它们都执行完后,主线程(老师)才能继续执行)
在jdk1.5之后,用CountDownLatch。
在JUC包下
它有几个方法:
new CountDownLatch(int)
countDown()
await()
在CountDownLatch中,有的线程在倒计时countDown(),有的线程在等待倒计时结束await()
倒计时的线程调用countDown()并不会阻塞,调用await()等待倒计时结束的线程(即main线程)会自我阻塞。计数器为零时,main线程会被唤醒并继续执行。
举个例,关于CountDownLatch的最基本使用:
其他6个线程执行完毕(被灭后)后,让counDownLatch调用一下countDown()方法
统一华夏的那步操作在counDownLatch调用await()方法后执行。
一共有几个国要被灭,写在构造函数中确定
二、CyclicBarrier(循环屏障)-jdk1.5
怎么理解上面这句话: 七个人到齐了才开会。(即等待的是这一个个线程,而CountDownLatch等待的是最后这个主线程)
做的是加法,而CountDownLatch做的是减法。
CyclicBarrier在JUC包下
召唤神龙的那步操作在CyclicBarrier的构造函数中写;
集齐龙珠的线程收集了自己该收集的龙珠操作后,在自己线程体内让 cyclicBarrier对象调用一下await()方法;
其他就不用做什么了。
一共要收集多少颗龙珠,写在构造函数中确定
三、Semaphore-jdk1.5
Semaphore 是一个计数信号量,必须由获取它的线程释放。
当资源数远大于实际需求的时候,Semaphore实际限制的是可以访问某些资源的线程数量
当资源数远小于实际需求的时候,Semaphore实际是说明了可以访问的某些资源的数量
可以代替synchronized和lock
demo:六个车(线程)抢3个车位(资源)
semaphore是可伸缩的,可变大可变小
补充:
四、Exchanger-jdk1,5
Exchanger 是 JDK 1.5 开始提供的一个用于两个工作线程之间交换数据的封装工具类,简单说就是一个线程在完成一定的事务后想与另一个线程交换数据,则第一个先拿出数据的线程会一直等待第二个线程,直到第二个线程拿着数据到来时才能彼此交换对应数据。其定义为 Exchanger<V> 泛型类型,其中 V 表示可交换的数据类型,对外提供的接口很简单,具体如下:
* Exchanger():无参构造方法。
* V exchange(V v):等待另一个线程到达此交换点(除非当前线程被中断),然后将给定的对象传送给该线程,并接收该线程的对象。
* V exchange(V v, long timeout, TimeUnit unit):等待另一个线程到达此交换点(除非当前线程被中断或超出了指定的等待时间),然后将给定的对象传送给该线程,并接收该线程的对象。
可以看出,当一个线程到达 exchange 调用点时,如果其他线程此前已经调用了此方法,则其他线程会被调度唤醒并与之进行对象交换,然后各自返回;如果其他线程还没到达交换点,则当前线程会被挂起,直至其他线程到达才会完成交换并正常返回,或者当前线程被中断或超时返回。