JDK当中除了以上的ReentrantLock和Condition之外,还有很多帮助猿友们协调线程的工具类。
CountDownLatch(计数器闭锁) 简单记忆:小明被老师罚站(一个线程await),要等所有同学走后(设置的参数被其他线程countdown()到0)小明才能回家(执行await()之后的代码)。
CyclicBarrier(可循环使用的屏障)简单记忆:一场规定好人数的百米田径比赛(new CyclicBarrier(int n)),要等所有人都在起跑线上准备好(所有线程阻塞在await()方法)之后,才一起出发(执行await()之后的代码)
Semaphore简单记忆:厕所里3个坑,10个人一块来上厕所,每次只能进3个,出来一个(release()),再进一个(acquire()),想起了一个谜语:“大家排队上厕所,打一个城市名?”
Exchanger(交换器)简单记忆:黑社会a和黑社会b相约到废弃仓库交易(final Exchanger
1,CountDownLatch(计数器闭锁)
这个类是为了帮助猿友们方便的实现一个这样的场景,就是某一个线程需要等待其它若干个线程完成某件事以后才能继续进行。比如下面的这个程序
package concurrent;
import java.util.concurrent.CountDownLatch;
/**
* @author zuoxiaolong
*
*/
public class CountDownLatchTest {
public static void main(String[] args) throws InterruptedException {
//只有一个构造器,参数是
final CountDownLatch countDownLatch = new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
final int number = i + 1;
Runnable runnable = new Runnable() {
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
System.out.println("执行任务[" + number + "]");
countDownLatch.countDown();
System.out.println("完成任务[" + number + "]");
}
};
Thread thread = new Thread(runnable);
thread.start();
}
System.out.println("主线程开始等待...");
countDownLatch.await();
System.out.println("主线程执行完毕...");
}
}
这个程序的主线程会等待CountDownLatch进行10次countDown方法的调用才会继续执行。我们可以从打印的结果上看出来,尽管有的时候完成任务的打印会出现在主线程执行完毕之后,但这只是因为countDown已经执行完毕,主线程的打印语句先一步执行而已。
分析一下这个CountDownLatch这个类,CountDownLatch是一个计数器闭锁,主要的功能就是通过await()方法来阻塞住当前线程,然后等待计数器减少到0了,再唤起这些线程继续执行。 这个类里主要有两个方法,一个是向下减计数器的方法:countdown(),其实现的核心代码如下:
public boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
很简单,如果取得当前的状态为0,说明这个锁已经结束,直接返回false;如果没有结束,然后去设置计数器减1,如果compareAndSetState不成功,则继续循环执行。 而其中的一直等待计数器归零的方法是await()。
2,CyclicBarrier
这个类是为了帮助猿友们方便的实现多个线程一起启动的场景,就像赛跑一样,只要大家都准备好了,那就开始一起冲。比如下面这个程序,所有的线程都准备好了,才会一起开始执行。
package concurrent;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* @author zuoxiaolong
*
*/
public class CyclicBarrierTest {
public static void main(String[] args) {
final CyclicBarrier cyclicBarrier = new CyclicBarrier(10);
for (int i = 0; i < 10; i++) {
final int number = i + 1;
Runnable runnable = new Runnable() {
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
System.out.println("等待执行任务[" + number + "]");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
} catch (BrokenBarrierException e) {
}
System.out.println("开始执行任务[" + number + "]");
}
};
Thread thread = new Thread(runnable);
thread.start();
}
}
}
3,Semaphore(旗语)
这个类是为了帮助猿友们方便的实现控制数量的场景,可以是线程数量或者任务数量等等。来看看下面这段简单的代码。
package concurrent;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author zuoxiaolong
*
*/
public class SemaphoreTest {
public static void main(String[] args) throws InterruptedException {
final Semaphore semaphore = new Semaphore(10);
final AtomicInteger number = new AtomicInteger();
for (int i = 0; i < 100; i++) {
Runnable runnable = new Runnable() {
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
try {
semaphore.acquire();
number.incrementAndGet();
} catch (InterruptedException e) {}
}
};
Thread thread = new Thread(runnable);
thread.start();
}
Thread.sleep(10000);
System.out.println("共" + number.get() + "个线程获得到信号");
System.exit(0);
}
}
4,Exchanger
这个类是为了帮助猿友们方便的实现两个线程交换数据的场景,使用起来非常简单,看看下面这段代码。
package concurrent;
import java.util.concurrent.Exchanger;
/**
* @author zuoxiaolong
*
*/
public class ExchangerTest {
public static void main(String[] args) throws InterruptedException {
final Exchanger exchanger = new Exchanger();
Thread thread1 = new Thread(new Runnable() {
public void run() {
try {
System.out.println("线程1等待接受");
String content = exchanger.exchange("thread1");
System.out.println("线程1收到的为:" + content);
} catch (InterruptedException e) {}
}
});
Thread thread2 = new Thread(new Runnable() {
public void run() {
try {
System.out.println("线程2等待接受并沉睡3秒");
Thread.sleep(3000);
String content = exchanger.exchange("thread2");
System.out.println("线程2收到的为:" + content);
} catch (InterruptedException e) {}
}
});
thread1.start();
thread2.start();
}
}
两个线程在只有一个线程调用exchange方法的时候调用方会被挂起,当都调用完毕时,双方会交换数据。在任何一方没调用exchange之前,线程都会处于挂起状态。
参考 没听说过这些,就不要说你懂并发了,three。