一:CountDownLatch
CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能。
用法1:有一个任务A要等其他几个任务执行完后执行,任务A中调用await()方法(任务A线程就阻塞等待了),其他几个任务线程执行完调用countDown()方法,当countdown为0时,任务A线程就唤醒继续执行了。
用法2:也可以反过来,比如有N个任务需要等某一条件后才能继续执行,那就在N个任务中调用await()方法,条件达成后调用countDown()方法,那N个任务就能继续执行了 。
实例代码:
public static void main(String a[]){
int N =4;
final CountDownLatch countDownLatch = new CountDownLatch(1);
for(int i = 0;i<N;i++){
new MyThread("线程"+i,countDownLatch).start();
}
new Thread(new Runnable() {
@Override
public void run() {
long waitTime = new Random().nextInt(3000);
try {
Thread.sleep(waitTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print("main waitTime:"+waitTime);
countDownLatch.countDown();
}
}).start();
}
static class MyThread extends Thread implements Runnable {
CountDownLatch countDownLatch;
MyThread(String name,CountDownLatch countDownLatch){
this.countDownLatch=countDownLatch;
this.setName(name);
}
@Override
public void run() {
System.out.print(getName()+" wait");
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print(getName()+" goon");
}
}
二:CyclicBarrier
用法一:比如有N个任务线程,new 一个CyclicBarrier对象,传入参数N,每个线程执行到一定代码调用await()方法,线程就挂起,当全部线程都调用了await()方法后,所有线程就唤醒继续执行了。
实例代码:
public static void main(String a[]){
int N =4;
CyclicBarrier cyclicBarrier = new CyclicBarrier(N);
for(int i = 0;i<N;i++){
new MyThread("线程"+i,cyclicBarrier).start();
}
}
static class MyThread extends Thread implements Runnable {
CyclicBarrier cyclicBarrier;
MyThread(String name,CyclicBarrier cyclicBarrier){
this.cyclicBarrier=cyclicBarrier;
this.setName(name);
}
@Override
public void run() {
System.out.print(getName()+" wait");
long waitTime = new Random().nextInt(3000);
try {
Thread.sleep(waitTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print(getName()+"waitTime:" + waitTime);
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.print(getName()+" goon");
}
}
用法二:创建对象时可以传入一个runnable对象,唤醒时先执行runnalble,再继续执行各自线程任务。
三:Semaphore
Semaphore可以控同时访问的线程个数。
用法:比如有个方法同时只能两个线程同时访问,那N个任务线程,执行前先调用acquire() 获取一个许可,获取到了就能继续,没获取到就等待,当然执行完记得调用release() 释放一个许可,让其他线程能进去。