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

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

业务需求1:有二十人去火车站买火车票,但只有两个窗口,需要控制,同时买票只能有两个人。当2个人中任意一个买好票离开之后,等待的18个人中又会有一个人可以占用窗口买票。
拆解:20个人是不是就是20个线程;2个窗口就是资源。
实际含义:怎么控制同一时间的并发数为2。
Semaphore信号量(控制并发线程数):
应用场景:1.限流;2.资源访问需要控制(数据库连接,打印机的接口)

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class SemaphoreDemo {
    /**
     * 执行人物类,获取信号量和释放信号量
     */
    class SemaphoreRunnable implements Runnable {
        private Semaphore semaphore;  //信号量
        private int user; //记录第几个用户
        public SemaphoreRunnable(Semaphore semaphore, int user) {
            this.semaphore = semaphore;
            this.user = user;
        }
        @Override
        public void run() {
            try {
                //获取信号量许可
                semaphore.acquire();
                System.out.println("用户"+ user +"进入窗口,准备买票");
                Thread.sleep((long)(Math.random()*10000));
                System.out.println("用户"+ user +"买票完成,即将离开");
                Thread.sleep((long)(Math.random()*10000));
                System.out.println("用户"+ user +"离开窗口");
                semaphore.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void execute(){
        //定义窗口个数
        final Semaphore semaphore = new Semaphore(2);
        //线程池
        ExecutorService threadPool = Executors.newCachedThreadPool();
        //模拟20个用户买票
        for(int i = 0; i < 20 ;i ++) {
            //去买票
            threadPool.execute(new SemaphoreRunnable(semaphore,(i+1)));
        }
        threadPool.shutdown();;
    }

    public static void main(String[] args) {
        SemaphoreDemo semaphoreDemo = new SemaphoreDemo();
        semaphoreDemo.execute();
    }
}

业务需求2:
公司组织周末聚餐吃饭,首先员工们(线程)各自从家里到聚餐地点,全部到齐之后,才开始一起吃东西(同步点)。假如人员没有到齐(阻塞),到的人只能够等待,直到所有人都到齐之后才开始吃饭。

CyclicBarrier(可循环的障碍物)
场景:在多线程计算数据之后,最后需要合并结果。

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CyclicBarrierDemo {
    public static void main(String[] args) {
        //3个人聚餐
        final CyclicBarrier cb = new CyclicBarrier(3, new Runnable() {
            @Override
            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() {

                @Override
                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 + "吃完饭,准备回家。。。");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            };
            threadPool.execute(r);
        }
        threadPool.shutdown();
    }
}

业务需求三:绑架案,目的是为了用钱来赎人
张三团伙绑架了小乔,放言要1000万来赎人,
张三团伙和大乔同时到达约定的地点,然后一手交钱,一手交人
两个线程,在同一个点(阻塞点),交换数据
Exchanger 两个线程进行交换数据
场景:1.用于2个线程交换数据
           2.校对工作
 

import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExchangerDemo {
    public static void main(String[] args) {
        //交换器,交换String类型
        Exchanger<String> ec = new Exchanger<String>();
        ExecutorService threadPool = Executors.newCachedThreadPool();
        //张三团伙
        threadPool.execute(new Runnable(){

            @Override
            public void run() {
                try {
                    String returnStr = ec.exchange("小乔");
                    System.out.println("绑架者用小乔交换回:" + returnStr);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        //大乔
        threadPool.execute(new Runnable(){

            @Override
            public void run() {
                try {
                    String returnStr = ec.exchange("1000万");
                    System.out.println("大乔用1000万交换回:" + returnStr);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        threadPool.shutdown();

    }
}


CountDownLatch 倒计时计数器,有一个任务,他需要等待其他某几个任务执行完毕之后才能执行
 

import java.util.concurrent.CountDownLatch;

import static com.google.common.collect.ComparisonChain.start;

public class CountDownLatchDemo {

    public static void main(String[] args) {
        final CountDownLatch latch = new CountDownLatch(2);
        //任务1
        new Thread(){
            public void run() {
                try {
                    System.out.println("任务1正在执行任务...");
                    Thread.sleep((long) (Math.random() * 1000));
                    System.out.println("任务1执行完毕...");
                    latch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
        new Thread(){
            public void run() {
                try {
                    System.out.println("任务2正在执行任务...");
                    Thread.sleep((long) (Math.random() * 1000));
                    System.out.println("任务2执行完毕...");
                    latch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
        //主线程
        System.out.println("等待其他2个任务执行完毕,主线程才开始执行任务" + Thread.currentThread().getName() );
        try {
            latch.await();
            System.out.println("其他两个任务执行完毕,主线程执行任务:" + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/xiao__jia__jia/article/details/81139682