多线程并发同步场景及解决方案

Semaphore (信号量,控制并发线程数,限流)

模拟买票,只有2个售票窗口,排队买票

    private static void semaphoreTest() {
        final Semaphore semaphore = new Semaphore(2);

        ExecutorService executorService = Executors.newCachedThreadPool();

        for (int i = 0; i < 10; i++) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        //获取信号量
                        semaphore.acquire();
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "开始买票----");
                    try {
                        Thread.sleep((long) (Math.random() * 10000));
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + "买票结束,离开");

                    //释放信号量
                    semaphore.release();
                }
            });
        }

        executorService.shutdown();
    }

执行效果

pool-1-thread-1开始买票----
pool-1-thread-2开始买票----
pool-1-thread-1买票结束,离开
pool-1-thread-3开始买票----
pool-1-thread-2买票结束,离开
pool-1-thread-4开始买票----
pool-1-thread-3买票结束,离开
pool-1-thread-5开始买票----
pool-1-thread-5买票结束,离开
pool-1-thread-6开始买票----
pool-1-thread-6买票结束,离开
pool-1-thread-7开始买票----
pool-1-thread-4买票结束,离开
pool-1-thread-8开始买票----
pool-1-thread-7买票结束,离开
pool-1-thread-9开始买票----
pool-1-thread-8买票结束,离开
pool-1-thread-10开始买票----
pool-1-thread-10买票结束,离开
pool-1-thread-9买票结束,离开

Process finished with exit code 0

CyclicBarrier 可循环的障碍物,等待其它设定的所有线程共同到达某个阻塞点再共同执行某一任务(再往下执行),

模拟聚餐,需要等人齐了再一起吃饭

    private static void cyclicBarrierTest() {
        final CyclicBarrier cyclicBarrier = new CyclicBarrier(3, new Runnable() {
            @Override
            public void run() {
                System.out.println("人都到齐了,拍照合影...");
            }
        });

        ExecutorService executorService = Executors.newCachedThreadPool();

        for (int i = 0; i < 3; i++) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println(Thread.currentThread().getName() + "已经到达,当前已有" + cyclicBarrier.getNumberWaiting() + "到达");
                        cyclicBarrier.await();
                        System.out.println("人都到齐了,开始干饭");
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println(Thread.currentThread().getName()+"吃完了,准备离开...");
                    } catch (BrokenBarrierException | InterruptedException ex) {
                        ex.printStackTrace();
                    }
                }
            });
        }
        executorService.shutdown();
    }

执行效果

pool-1-thread-2已经到达,当前已有0到达
pool-1-thread-3已经到达,当前已有1到达
pool-1-thread-1已经到达,当前已有2到达
人都到齐了,拍照合影...
人都到齐了,开始干饭
人都到齐了,开始干饭
人都到齐了,开始干饭
pool-1-thread-2吃完了,准备离开...
pool-1-thread-1吃完了,准备离开...
pool-1-thread-3吃完了,准备离开...

Process finished with exit code 0

CountDownLatch 线程计数器,控制某一个任务需要等待几个线程执行后再执行

模拟主线程等待设定的线程执行完毕再执行

    private static void countDownLatchTest() {

        final CountDownLatch countDownLatch = new CountDownLatch(3);

        System.out.println("执行主线程");

        for (int i = 0; i < 3; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("开始执行线程" + Thread.currentThread().getName());
                    try {
                        Thread.sleep((long) (Math.random() * 10000));
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "执行结束");
                    countDownLatch.countDown();
                }
            }).start();
        }

        try {
            countDownLatch.await();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        System.out.println("继续执行主线程");
        try {
            Thread.sleep((long) (Math.random() * 10000));
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        System.out.println("主线程执行结束");
    }

执行效果

执行主线程
开始执行线程Thread-0
开始执行线程Thread-1
开始执行线程Thread-2
Thread-1执行结束
Thread-2执行结束
Thread-0执行结束
继续执行主线程
主线程执行结束

Process finished with exit code 0
Last Updated:
Contributors: EEDC