日常学习记录Java 常用线程并发类的应用实例

Posted 盛夏温暖流年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了日常学习记录Java 常用线程并发类的应用实例相关的知识,希望对你有一定的参考价值。

之前复习线程并发的时候曾经写过博客,对 ReentrantLock 的实现原理进行了详细的介绍,链接如下:

https://blog.csdn.net/j1231230/article/details/120572008

常用常新,趁着还没忘再回顾一下相关知识,保持学习的好习惯非常重要。

可以知道,ReentrantLock 实现的前提是 AbstractQueuedSynchronizer(抽象队列同步器),简称 AQS,是 java.util.concurrent 的核心,常用的线程并发类 CountDownLatch、CyclicBarrier、Semaphore 等都包括了一个继承自 AQS 抽象类的内部类。

本篇博客对这几个线程并发类 CountDownLatch、CyclicBarrier、Semaphore 的应用实例进行记录和介绍。


CountDownLatch

CountDownLatch(倒计时器):用来协调多个线程之间的同步。
比如在主线程中新建 n 个子线程,那 CountDownLatch 的参数需要设置的和线程数一致,当子线程都执行完成后,倒计时归零,此时等待的主线程才能继续执行。

代码应用实例

public class CountDownLatchDemo 

    public static void main(String[] args) throws InterruptedException 
        CountDownLatch countDownLatch = new CountDownLatch(2);
        new Thread() 
            @Override
            public void run() 
                try 
                    System.out.println("执行任务1");
                    Thread.sleep(1000);
                    System.out.println("执行任务1完毕");
                    countDownLatch.countDown();
                 catch (InterruptedException e) 
                    e.printStackTrace();
                

            
        .start();
        new Thread() 
            @Override
            public void run() 
                try 
                    System.out.println("执行任务2");
                    Thread.sleep(1000);
                    System.out.println("执行任务2完毕");
                    countDownLatch.countDown();
                 catch (InterruptedException e) 
                    e.printStackTrace();
                

            
        .start();

        countDownLatch.await();
        // 两个都执行完毕才执行
        System.out.println("exit");
    

运行结果如下所示:

我们在主线程中新建了 2 个子线程,这里的 CountDownLatch 的参数设置和子线程数保持一致,都是 2,当子线程都执行完成后倒计时归零,此时等待的主线程就能继续执行了,输出结果 “exit” 。


CyclicBarrier

CyclicBarrier(循环栅栏):它的功能比 CountDownLatch 更加复杂和强大,主要作用是让一组线程到达一个同步点时被阻塞,直到最后一个线程到达同步点时,屏障才会被解除。

举一个具体的例子,比如一个公司聚餐,每个员工都从家里出发,可以把每个人都看作是一个线程,每个线程调⽤ await() ⽅法告诉 CyclicBarrier 我已经到达了屏障,然后当前线程会被阻塞。等到最后一个员工到了(屏障解除),饭店才打开门让大家进去(线程才会开始工作)。

代码应用实例

public class CyclicBarrierDemo 
    public static void main(String[] args) 
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3, new Runnable() 
            @Override
            public void run() 
                System.out.println("全员到齐,开始吃饭!");
            
        );

        ExecutorService es = Executors.newCachedThreadPool();
        try 
            for (int i = 0; i < 3; i++) 
                int user = i + 1;
                Runnable r = new Runnable() 
                    @Override
                    public void run() 
                        try 
                            Thread.sleep(1000);
                            System.out.println("用户" + user + "已到达");
                            cyclicBarrier.await();
                            System.out.println("我去吃饭了!");
                         catch (Exception e) 
                            e.printStackTrace();
                        
                    
                ;
                es.submit(r);
            
        catch (Exception e)
            e.printStackTrace();
        finally 
            es.shutdown();
        
    

运行结果如下所示:

分析可以得知,用户2的线程先运行,在原地阻塞等待;之后用户3的线程运行,也进入等待状态,最后用户1的线程运行,此时屏障得以解除,3 个线程才会正式开始工作。


Semaphore

Semaphore (信号量):用来控制同时访问特定资源的线程数量,通过协调各个线程,以保证资源的合理利用。

代码应用实例

public class SemaphoreDemo 
    public static void main(String[] args) 
        int workers = 8;
        Semaphore semaphore = new Semaphore(5);
        for (int i=0; i<workers;i++)
            new Worker(i, semaphore).start();
        
    

class Worker extends Thread
    private Integer num;
    private Semaphore semaphore;

    public Worker(Integer num, Semaphore semaphore)
        this.num = num;
        this.semaphore = semaphore;
    

    @Override
    public void run()
        try 
            semaphore.acquire();
            System.out.println("工人" + this.num + ",占用了一台机器");
            Thread.sleep(2000);
            System.out.println("工人" + this.num + ",释放了一台机器");
            semaphore.release();
         catch (InterruptedException e) 
            e.printStackTrace();
        
    

运行结果如下所示:

以上实例中,共有 8 个工人访问 5 台工作机器,也就是说 8 个线程中可以有 5 个同时进行操作,此时剩下的 3 个线程需要等待,等有线程完成操作,资源空闲下来后,其他线程才可以继续使用。

以上是关于日常学习记录Java 常用线程并发类的应用实例的主要内容,如果未能解决你的问题,请参考以下文章

Java并发工具类同步屏障CyclicBarrier

Java并发多线程编程——CyclicBarrier

java并发之同步辅助类

Java并发工具类之同步屏障CyclicBarrier

Java并发学习

java多线程系列:通过对战游戏学习CyclicBarrier