1.CountDownLatch
CountDownLatch允许一个或者多个线程等待其他线程完成操作
比如这样一个需求:我们需要解析一个Excel里的多个sheet的数据,使用多线程每个线程分别解析一个sheet里的数据,等待所有的sheet解析完之后,程序提示解析完成,在这个需求中,要实现主线程等待所有线程完成sheet解析操作,最简单的是使用join方法
Join方法的作用:其实就是表示一旦某个线程调用了join方法,那么就要一直运行到该线程运行结束,才会运行其他进程
实现原理代码片段:
while(isAlive()){
wait(0)
}
如果join线程存活则让线程永远等待下去,wait(0)表示线程永远等待下去
public class JoinCountDownLatchTest {
public static void main(String[] args) throws InterruptedException {
Thread parser1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("parser1 finish");
}
});
Thread parser2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("parser2 finish");
}
});
parser1.start();
parser2.start();
parser1.join();
parser2.join();
System.out.println("all parser finish");
}
}
而CountDownLatch也可以实现join的功能,并且比join的功能更多
-
countDownLatch的构造函数可以接收一个int类型的参数作为计数器
-
计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了
-
countDown():计数器的值减一
-
await():等待计数器归零,然后再向下执行
import java.util.concurrent.CountDownLatch;
public class CountDownLatchTest {
static CountDownLatch c = new CountDownLatch(2);
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(1);
c.countDown();
System.out.println(2);
c.countDown();
}
}).start();
c.await();
System.out.println(3);
}
}
2.CycliBarrier
CycliBarrier这个单词的字面意思是可循环使用的屏障的。
它的功能是:让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被阻塞的线程才能执行下去。
- 构造函数 CyclicBarrier(int parties) 屏障拦截的线程数量
- await() 调用该方法时表示线程已经到达屏障,随即阻塞
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierTest {
public static void main(String[] args) {
CyclicBarrier c = new CyclicBarrier(7,()->{
System.out.println("召唤神龙");
});
for (int i = 1; i <=7 ; i++) {
int finalI = i;
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"收集"+finalI+"个龙珠");
try {
c.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
以上两种的区别:
-
CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()方法重置
-
CountDownLatch相当于减法计数器,CyclicBarrier相当于加法计数器
3.Semaphore
Semaphore(信号量)是用来控制同时访问特定资源的线程数量
Semaphore 的构造方法需要传入一个参数,如 new Semaphore(10)
表示最多有10个线程可以获取到信号量,10个之后的线程再尝试获取时就会被阻塞。
获取信号量使用:s.acquire()方法;
释放信号量使用:s.release()方法。
只有前边的线程释放掉后,后面的线程(10个之后)才能被唤醒,重新获取信号量
假设有三个车位,此时有六辆车需要停车:
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class SemaphoreTest {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
for(int i=1;i<=6;i++){
new Thread(()->{
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"抢到车位");
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+"离开车位");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}).start();
}
}
}