CountDownLatch、CyclicBarrier、Semaphore
{
"title":"AQS相关",
"date":2020-05-21T09:16:43+08:00,
"draft":true,
"tags":["CountDownLatch、CyclicBarrier、Semaphore"],
"comments":true,
"share":true
}
AQS 简单介绍
AQS 原理
CountDownLatch相关
CountDownLatch:让一些线程阻塞直到另外一些完成后才被唤醒。代码演示。
CountDownLatch主要有两个方法,当一个或多个线程调用await()方法时,调用线程会被阻塞。
其他线程调用countDown()方法计数器减1(调用countDown方法时线程不会阻塞),当计数器的值变为0,
因调用await方法被阻塞的线程会被唤醒,继续执行。
package com.xpf.Interview.juc.other;
import java.util.concurrent.CountDownLatch;
/**
* @Author: Xia
* @Date: 2020/5/21 9:30
* @Email:x2358114512@163.com
代码实现:等for里的线程完成结束后,main线程才能执行。
*/
public class T {
public static void main(String[] args) {
notcountDownLatch();
countDownLatch();
}
private static void countDownLatch() {
CountDownLatch countDownLatch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName()+"线程完成任务,回家");
countDownLatch.countDown();
},String.valueOf(i)).start();
}
try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println(Thread.currentThread().getName()+"线程完成任务,回家");
}
private static void notcountDownLatch() {
for(int i = 0;i<5;i++){
new Thread(() -> {
System.out.println(Thread.currentThread().getName()+"线程完成任务,回家");
},String.valueOf(i)).start();
}
System.out.println(Thread.currentThread().getName()+"线程完成任务,回家");
}
}
notcountDownLatch()函数的结果:
0线程完成任务,回家
3线程完成任务,回家
1线程完成任务,回家
main线程完成任务,回家
2线程完成任务,回家
4线程完成任务,回家
countDownLatch()函数的结果:
0线程完成任务,回家
1线程完成任务,回家
2线程完成任务,回家
4线程完成任务,回家
3线程完成任务,回家
main线程完成任务,回家- CyclicBarrier相关
CyclicBarrier的字面意思是可循环(Cyclic)使用的屏障(barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫做同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。线程进入屏障通过CyclicBarrier的await()方法。代码演示。
1. 线程进入屏障通过CyclicBarrier的await()方法。
2. 构造方法:public CyclicBarrier(int parties, Runnable barrierAction)
Runnable barrierAction指的是被阻塞的哪个线程
package com.xpf.Interview.juc.other;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* @Author: Xia
* @Date: 2020/5/21 9:30
* @Email:x2358114512@163.com
*/
public class T {
public static void main(String[] args) {
cyclicBarrier();
}
private static void cyclicBarrier() {
CyclicBarrier cyclicBarrier = new CyclicBarrier(5,() -> {
System.out.println(Thread.currentThread().getName()+"线程:前5个线程完成后,最后才会完成此线程");
});
for (int i = 0; i < 5; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName()+"线程:完成任务");
try { cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); }
},String.valueOf(i)).start();
}
}
}
cyclicBarrier()函数执行结果:
0线程:完成任务
2线程:完成任务
3线程:完成任务
1线程:完成任务
4线程:完成任务
4线程:前5个线程完成后,最后才会完成此线程- Semaphore相关
引出问题:之前的案列都是多线程访问同一份共享资源;对于多线程访问多份共享资源那怎么处理?
这里就可以引出Semaphore。
Semaphore(信号量)的作用:用于多线程调用多个共享资源的互斥使用,另外也可以用于并发线程数的控制。
package com.xpf.Interview.juc.other;
import java.sql.Time;
import java.util.concurrent.*;
/**
* @Author: Xia
* @Date: 2020/5/21 9:30
* @Email:x2358114512@163.com
模拟5个车(5个线程)抢3个车位(3个资源)
*/
public class T {
public static void main(String[] args) {
semaphore();
}
private static void semaphore() {
Semaphore semaphore = new Semaphore(3); //模拟3个停车位(资源)
for (int i = 0; i < 5; i++) { //模拟5部汽车(线程)
new Thread(() -> {
try{
semaphore.acquire(); //当前线程抢到资源
System.out.println(Thread.currentThread().getName()+"线程:抢到停车位");
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+"线程:2秒后离开停车位");
}catch (Exception e){
e.printStackTrace();
}finally {
semaphore.release(); //当前线程释放资源
}
},String.valueOf(i)).start();
}
}
}
semaphore()函数执行结果:
0线程:抢到停车位
1线程:抢到停车位
2线程:抢到停车位
0线程:2秒后离开停车位
2线程:2秒后离开停车位
3线程:抢到停车位
4线程:抢到停车位
1线程:2秒后离开停车位
3线程:2秒后离开停车位
4线程:2秒后离开停车位
查看14道真题和解析