多线程并发同步业务场景与解决方案

1)semaphore 信号量 (控制并发数) 业务场景1:假如现在有10个人去同一家公司面试,但是只有3个面试官,那么同一时间只有2个人面试,当3个人中的任意一个面试结束之后,等待的7个人又会有一个人可以去面试。
需求分析:人数=线程数面试官=资源正在面试=线程正在执行
面试结束=线程执行结束等待面试人数=线程阻塞
解决方案:信号量 semaphore
代码Demo:
public class SemaphoreTest implements Runnable {
private int num;
private Semaphore semaphore;
public SemaphoreTest(int num,Semaphore semaphore){
this.num=num;
this.semaphore=semaphore;
}
public void run() {
try {
semaphore.acquire(); //获取信号量许可,才能进入
System.out.println("面试者"+num+"进入房间……");
Thread.sleep((long)Math.random()*10000);
System.out.println("面试者"+num+"交谈中……");
Thread.sleep((long)Math.random()*10000);
System.out.println("面试者"+num+"离开房间……");
semaphore.release(); //释放信号量许可
} catch (InterruptedException e) {
e.printStackTrace();
} }
public static void main(String[] args) {
final Semaphore s=new Semaphore(3); //并发数为3
ExecutorService threadPool=Executors.newCachedThreadPool(); //线程池
for(int i=0; i<10; i++){
threadPool.execute(new SemaphoreTest((i+1),s));
}
threadPool.shutdown();
} }
2)Cyclicbarrier同步屏障(用于多线程计算数据,最后合并计算结果) 业务场景2:公司周末组织去聚餐、首先各自从家里出发到聚餐地点,当所有人全部到齐之后才开始吃饭,如果未到齐,到的人就只能等待在那里,直到所有人都到达之后,才可以一起做事。
案例代码:
public class CyclicbarrierDemo {
public static void main(String[] args) {
final CyclicBarrier cb=new CyclicBarrier(3,new Runnable() {
public void run() {
System.out.println("吃饭前,一起做的事情"); } });
ExecutorService threadPool=Executors.newCachedThreadPool(); //线程池
for(int i=0; i<3; i++){
final int user=i+1;
Runnable r=new Runnable() {
public void run() {
try {
Thread.sleep((long)Math.random()*10000);
System.out.println(user+"到达聚餐地点,当前已有"+(cb.getNumberWaiting()+1)+"人到达");
cb.await(); //等待,只有当线程都到达之后,才能往下走
if(user==1){ System.out.println("人员到齐"); }
Thread.sleep((long)Math.random()*10000);
System.out.println(user+"吃完饭,回家……");
//dosometing
} catch (Exception e) {
e.printStackTrace(); } } };
threadPool.execute(r);
}
threadPool.shutdown();
} }
3)Exchanger 线程之间交换数据 public class ExchangerDemo {
public static void main(String[] args) {
final Exchangerexchanger=new Exchanger();
【多线程并发同步业务场景与解决方案】 ExecutorService threadPool=Executors.newCachedThreadPool(); //线程池
threadPool.execute(new Runnable() {
public void run() { String sc="a";
try {
String js=exchanger.exchange(sc); //js=b
} catch (InterruptedException e) { e.printStackTrace(); } } });
threadPool.execute(new Runnable() {
public void run() {
String sc="b";
try { String js=exchanger.exchange(sc); //js=a
} catch (InterruptedException e) { e.printStackTrace(); } } }); } }
执行后,连个线程的数据进行了交换。
4)CountDownLatch 倒计时器 业务场景4:有一个任务a,他需要等待其他几个任务(BCD)都执行完毕之后才能来执行这个任务。
public static void main(String[] args) throws InterruptedException {
final CountDownLatch latch=new CountDownLatch(3);
new Thread(){
public void run() {
System.out.println("子任务B"+Thread.currentThread().getName()+"正在执行"); latch.countDown(); //倒计时减一
}; }.start();
new Thread(){
public void run() {
System.out.println("子任务C"+Thread.currentThread().getName()+"正在执行"); latch.countDown(); //倒计时减一
}; }.start();
new Thread(){
public void run() {
System.out.println("子任务D"+Thread.currentThread().getName()+"正在执行"); latch.countDown(); //倒计时减一
}; }.start();
System.out.println("等待3个任务执行完毕,"+Thread.currentThread().getName()+"组任务开始执行。");
latch.await();
System.out.println("继续执行主任务!");
}
CountDownLatch 与Cyclicbarrier 的区别:
1)共同点:都能够实现线程之间的等待。
2)不同点:
CountDownLatch :1)一般用于某个线程A等待其他若干线程执行完任务后,它才能执行。2)它是不能够重复用的。
Cyclicbarrier :1)一般用于一组线程互相等待,然后这一组线程同时执行。2)它可以重复使用。

    推荐阅读