码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • Java多线程(7):JUC(上)


    您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~

     

    前面把线程相关的生命周期、关键字、线程池(ThreadPool)、ThreadLocal、CAS、锁和AQS都讲完了,现在就剩下怎么来用多线程了。而要想用好多线程,其实是可以取一些巧的,比如JUC(好多面试官喜欢问的JUC,就是现在要讲的JUC)。JUC就是java.util.concurrent的首字母缩写,它是Java并发工具包就是中提供的各种工具类的统称,主要分为几大类:

    1、同步器;

    2、线程安全的容器;

    3、阻塞队列;

    4、一些特殊的类。

    他们都有各自适合应用场景。这里是并发工具包相关类的继承结构:

     

     

     

     

     

    下面从同步器开始。

    常用的JUC同步器有四个:

    1、CountDownLatch:字面意思是倒计时锁,如果有“倒计时”的需求,那么CountDownLatch是最好的工具。它还有一个别称:发令枪。可以想象一下,火箭点火发射的时候,所有设备、部门都会依次检查确认,如果全部都确认准备好了才能开始发射,也就是等倒数到指定的数字(一般是0)的时候,就开始执行预设动作;

    2、Semaphore:字面意思信号量,好比红绿灯,或者就餐排队时餐馆发的数字序号,一次只允许若干个线程执行。这个在昨天的例子里面也已经演示过了,而且还是通过自定义AQS来实现的(信号量可能不太好理解,我更倾向于叫它摇号器);

    3、CyclicBarrier:字面意思是屏障或者栅栏,与CountDownLatch比较像,但它侧重于工作本身,即指定的若干个工作都满足考核标准(某个屏障)之后,才能继续进行下面的工作,且可反复使用;

    4、Exchanger:用于线程之间交换数据,更形象地说法是“交换机”,即当一个线程完成某项工作后想与另一个线程交换数据,就可以使用这个工具类。

    下面来一个个地演示它们的用法。

     

    一、CountDownLatch

    CountDownLatch的功能如果用图来表示的话,就会是这样的:

     

     

     

     

    CountDownLatch实例代码:

    复制代码
    /**
     * 发令枪
     *
     * @author 湘王
     */
    public class CountDownLatchTester implements Runnable {
        static final CountDownLatch latch = new CountDownLatch(10);
        @Override
        public void run() {
            // 检查任务
            try {
                System.out.println(Thread.currentThread().getName() + " 检查完毕!");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                latch.countDown();
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            ExecutorService executor = Executors.newFixedThreadPool(5);
            for (int i = 10; i > 0; i--) {
                Thread.sleep(1000);
                executor.submit(new CountDownLatchTester());
                System.out.println(i);
            }
    
            Thread.sleep(1000);
            // 检查
            latch.await();
    
            System.out.println();
            System.out.println("点火,发射!");
            // 关闭线程池
            executor.shutdown();
        }
    }
    复制代码

     

     

    执行CountDownLatch的效果是:

     

     

     

     

    二、Semaphore

    Semaphore的功能如果用图来表示的话,就会是这样的:

     

     

     

     

     

    Semaphore实例代码:

     

    复制代码
    /**
     * 信号量(摇号器)
     *
     * @author 湘王
     */
    public class SemaphoreTester implements Runnable {
        static final Semaphore semaphore = new Semaphore(3);
    
        @Override
        public void run() {
            try {
                semaphore.acquire();
                System.out.println(Thread.currentThread().getName() + " 开始进餐");
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            semaphore.release();
        }
    
        public static void main(String[] args) {
            ExecutorService excutor = Executors.newFixedThreadPool(15);
            for (int i = 0; i < 15; i++) {
                excutor.submit(new SemaphoreTester());
            }
            excutor.shutdown();
        }
    }
    复制代码

     

     

    Semaphore执行后的效果是:

     

     

     

     

     

    三、CyclicBarrier

    CyclicBarrier的功能如果用图来表示的话,就会是这样的:

     

     

     

     

     

    CyclicBarrier实例代码:

    复制代码
    /**
     * 栅栏
     *
     * @author 湘王
     */
    public class CyclicBarrierTester implements Runnable {
        private final static CyclicBarrier barrier = new CyclicBarrier(3);
    
        @Override
        public void run() {
            try {
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + " 已达到预定位置,等待指令...");
                // 只有最后一个线程执行后,所有的线程才能执行2
                barrier.await();
                Thread.sleep(1000);
                // 2 所有线程都会执行的动作
                System.out.println(Thread.currentThread().getName() + " 已突破第一道封锁线");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            ExecutorService executor = Executors.newFixedThreadPool(3);
            for (int i = 0; i < 15; i++) {
                executor.submit(new CyclicBarrierTester());
            }
            // 关闭线程池
            executor.shutdown();
        }
    }
    复制代码

     

     

    CyclicBarrier执行后的效果是:

     

     

     

    四、Exchanger

    Exchanger的功能如果用图来表示的话,就会是这样的:

     

     

     

     

     

    Exchanger实例代码:

     

    复制代码
    /**
     * 交换机
     *
     * @author 湘王
     */
    public class ExchangerTester implements Runnable {
        Exchanger exchanger = null;
        Object object = null;
    
        public ExchangerTester(Exchanger exchanger, Object object) {
            this.exchanger = exchanger;
            this.object = object;
        }
    
        @Override
        public void run() {
            try {
                Object previous = this.object;
                this.object = this.exchanger.exchange(this.object);
                System.out.println(Thread.currentThread().getName() + " 用对象 " + previous + " 换对象 " + this.object);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            Exchanger exchanger = new Exchanger();
            ExchangerTester tester1 = new ExchangerTester(exchanger, "A");
            ExchangerTester tester2 = new ExchangerTester(exchanger, "B");
    
            new Thread(tester1).start();
            new Thread(tester2).start();
        }
    }
    
    复制代码

     

     

    Exchanger执行后的效果是:

     

     

     

     

    把这四种同步器掌握好(包括它们的组合使用),几乎可以解决90%以上的使用多线程的场景问题,再也不用担心不会多线程了。

     

     


     

     

    感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~

     

  • 相关阅读:
    【Oculus Interaction SDK】(九)使用控制器时显示手的模型
    Python配置与测试利器:Hydra + pytest的完美结合
    webpack-bundle-analyzer 插件配置
    WebGL笔记:图形转面的原理与实现
    OSPF基础:OSPF工作原理以及优点、OSPF的缺点、OSPF配置方法、DR与BDR的选举原理
    Frontiers | 北林邬荣领/何晓青-网络作图揭示拟南芥与叶际微生物组互作机制
    软考__第17章 战略管理
    设计模式详解(十二)——外观模式
    Linux内核完全注释(基于Linux0.11)_笔记_Linux0.11执行流程
    Jenkins集成maven
  • 原文地址:https://www.cnblogs.com/xiangwang1111/p/16846002.html
    • 最新文章
    • 沪漂五周年了:我越来越迷茫了
      Agentic Skill Routing 实战:别再把所有 Skill 塞进 AI Agent 上下文
      MySQL-Seconds_behind_master的精度误差
      [MAF预定义ChatClient中间件-03]CachingChatClient——利用缓存省钱省时间
      AI的至暗历史:从万众期待到被政府撤资,AI的两次死亡徘徊
      Agent OS :五种驯服不确定性的范式
      PortSwigger SQL注入LAB11
      数据库即时编译JIT
      [Begin]AI Learn Data Day 0
      深度学习进阶(二十七)现代 LLM 的核心架构设计其二:SwiGLU
    • 热门文章
    • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
      奉劝各位学弟学妹们,该打造你的技术影响力了!
      五年了,我在 CSDN 的两个一百万。
      Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
      面试官都震惊,你这网络基础可以啊!
      你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
      心情不好的时候,用 Python 画棵樱花树送给自己吧
      通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
      13 万字 C 语言从入门到精通保姆级教程2021 年版
      10行代码集2000张美女图,Python爬虫120例,再上征途
    小工具 小游戏
    Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1

    京公网安备 11010502049817号