详情链接
https://www.taodudu.cc/news/show-60458.html
前言
JUC中提供了三种常用的辅助类,通过这些辅助类可以很好的解决线程数量过多时Lock锁的频繁操作。这三种辅助类为:
- CountDownLatch
- CyclicBarrier
- Semaphore
1.CountDownLatch
下图是Jdk1.8中解释的CountDownLatch类功能,简单而言,在实例化时,需要传入一个信号量,每当一个线程执行后,信号量减1,当信号量为0时,释放阻塞的线程。
用个小Demo模拟,需求是启动5个线程,当5个线程执行完后,main线程才能继续执行,如果不使用CountDownLatch,线程的调用将不可控。
public static void main(final String[] args) throws InterruptedException {
for (int i = 0; i < 5; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t 执行");
}, String.valueOf(i)).start();
}
System.out.println(Thread.currentThread().getName() + "最终执行");
}
可以看出,不使用任何线程控制等方法,线程是随计算机调度的,线程的执行顺序并不是我们预期希望的。
当使用CountDownLatch,实例化时将信号量设置为5,每当一个线程执行后,信号量减1,当5个线程执行完后,信号量为0,main线程才执行。
public static void main(final String[] args) throws InterruptedException {
//实例化,并传入信号初始量
CountDownLatch countDownLatch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t 执行");
//信号量减1
countDownLatch.countDown();
}, String.valueOf(i)).start();
}
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + "最终执行");
}
2.CyclicBarrier
下图是Jdk1.8中解释的CyclicBarrier类功能,简单而言,在实例化时,需要传入一个信号量和Runnable接口,每当一个线程执行后,信号量加1,当信号量的值达到传入的预期值,则执行方法。
这里我们定义了只要达到3个线程,就执行方法。
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> {
System.out.println("---------方法执行---------");
});
for (int i = 0; i < 3; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t执行");
try {
cyclicBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}, String.valueOf(i)).start();
}
}
3. Semaphore(信号灯)
比如:停车6个车3车位,银行排队10个人3窗口。
下图为Jdk1.8文档中的解释,简单来说,在初始化时设定一个预期值,当线程数量达到预期值,其他线程被阻塞,只有当线程使用完毕,其他线程才能重新开始抢占资源。
public static void main(String[] args) {
Semaphore Semaphore = new Semaphore(3);
for (int i = 0; i < 5; i++) {
new Thread(() -> {
try {
Semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "\t抢占到资源");
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + "\t释放了资源");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
Semaphore.release();
}
}, String.valueOf(i)).start();
}
}
从运行结果中很容易理解,我们定义了初始值为3,说明只要有3个线程抢占到资源,直到他们释放,其他资源都只能等待。
Semaphore是对锁的扩展。无论是内部锁synchronized还是重入锁ReentranLock,一次都只允许一个线程访问一个资源,而信号量却可以指定多个线程,同时访问某一个资源。一定记得release()。