Java_23_并发包

这篇具有很好参考价值的文章主要介绍了Java_23_并发包。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

并发包

  1. 并发包的来历:
    在实际开发中如果不需要考虑线程安全问题,大家不需要做线程安全,因为如果做了反而性能不好!
    但是开发中有很多业务是需要考虑线程安全问题的,此时就必须考虑了。否则业务出现问题。
    Java为很多业务场景提供了性能优异,且线程安全的并发包,程序员可以选择使用!

  2. Map集合中的经典集合:HashMap它是线程不安全的,性能好

    1. 如果在要求线程安全的业务情况下就不能用这个集合做Map集合,否则业务会崩溃~
    2. 为了保证线程安全,可以使用Hashtable。注意:线程中加入了计时
    3. Hashtable是线程安全的Map集合,但是性能较差!(已经被淘汰了,虽然安全,但是性能差)
    4. 为了保证线程安全,再看ConcurrentHashMap(不止线程安全,而且效率高,性能好,最新最好用的线程安全的Map集合)
    5. ConcurrentHashMap保证了线程安全,综合性能较好!
  3. 小结:
    HashMap是线程不安全的。
    Hashtable线程安全基于synchronized,综合性能差,被淘汰了。
    ConcurrentHashMap:线程安全的,分段式锁,综合性能最好,线程安全开发中推荐使用

HashMap线程不安全验证及解决方案

public class ConcurrentHashMapDemo01 {
    //演示HashMap在高并发下的线程不安全性
    public static Map<String ,String> maps = new HashMap<>();

    public static void main(String[] args){
        Runnable target = new MyRunnable();
        Thread t1 = new Thread(target,"Thread-01");
        Thread t2 = new Thread(target,"Thread-02");

        t1.start();
        t2.start();

        try {
            t1.join();  //让两个线程跑完 使主线程不抢t1的CPU
            t2.join();  //只能t1,t2两个互相抢
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        //等线程执行完毕获取集合最终元素个数
        System.out.println("元素个数:" + maps.size());
    }
}
class MyRunnable implements Runnable{
    @Override
    public void run(){
        for(int i = 1;i <= 500000;i ++){  //第一个线程加了50万,第二个线程也加了50万
            ConcurrentHashMapDemo01.maps.put(Thread.currentThread().getName() + i,Thread.currentThread().getName() + i);
        }
    }
}

输出结果:元素个数:947823 不是1000000

public static Map<String ,String> maps = new Hashtable<>();

定义成这种线程就安全了,但性能差,源码全是加锁
Java_23_并发包,Java基础教程,java,开发语言

public static Map<String ,String> maps = new ConcurrentHashMap<>();//线程安全,性能得到极大提升

Java_23_并发包,Java基础教程,java,开发语言

CountDownLatch并发包

  1. CountDownLatch允许一个或多个线程等待其他线程完成操作,再执行自己。

    1. 例如:线程1要执行打印:A和C,线程2要执行打印:B,但线程1在打印A后,要线程2打印B之后才能打印C,所以:线程1在打印A后,必须等待线程2打印完B之后才能继续执行
  2. 需求:
    提供A线程,打印 A , C
    提供B线程,打印 B

  3. 构造器:
    public CountDownLatch(int count)// 初始化唤醒需要的down几步。

  4. 方法:
    public void await() throws InterruptedException// 让当前线程等待,必须down完初始化的数字才可以被唤醒,否则进入无限等待
    public void countDown() // 计数器进行减1 (down 1)

  5. 小结:
    CountDownLatch可以用于让某个线程等待几步才可以继续执行, 从而可以实现控制线程执行的流程
    创建了几个Down就要c.countDown();几次,否则会出错!!!

public class CountDownLatchDemo01 {
    public static void main(String[] args) {
        //创建countdownlatch对象用于监督A、B线程执行情况_监督
        CountDownLatch c = new CountDownLatch(1);
        new MyThread_A(c).start();
        new MyThread_B(c).start();
    }
}
class MyThread_A extends Thread{
    private CountDownLatch c;

    public MyThread_A(CountDownLatch c) {
        this.c = c;
    }

    @Override
    public void run(){
        System.out.println("A");
        //等待自己,当前线程让出CPU等待自己
        try {
            c.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("C");
    }
}
class MyThread_B extends Thread{
    private CountDownLatch c;

    public MyThread_B(CountDownLatch c) {
        this.c = c;
    }

    @Override
    public void run(){
        System.out.println("B");
        c.countDown(); //让计数器减1,被等待的线程就唤醒了
    }
}

CyclicBarrier并发包

  1. CyclicBarrier作用:
    某个线程任务必须等待其他线程执行完毕以后才能最终触发自己执行。
  2. 例如:公司召集5名员工开会,等5名员工都到了,会议开始。
    我们创建5个员工线程,1个开会任务,几乎同时启动
    使用CyclicBarrier保证5名员工线程全部执行后,再执行开会线程。
  3. 构造器:
    public CyclicBarrier(int parties, Runnable barrierAction)
    // 用于在线程到达屏障5时,优先执行barrierAction,方便处理更复杂的业务场景
  4. 方法:
    public int await()
    // 每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞
  5. 小结:
    可以实现多线程中,某个任务在等待其他线程执行完毕以后触发。
    循环屏障可以实现达到一组屏障就触发一个任务执行!
public class CyclicBarrierDemo01 {
    public static void main(String[] args) {
        //2.创建循环屏障对象,等到5个线程执行完毕后触发一次线程任务(开会)
        CyclicBarrier c = new CyclicBarrier(5,new Meeting() );
        //1.创建一个任务循环屏障对象
        for(int i = 1;i <= 10;i ++){
            try {
                Thread.sleep(1000);

            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            new EmployeeThread("Employee-" + i,c).start();
        }
    }
}
class Meeting implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "开始组织会议!");
    }
}
class  EmployeeThread extends Thread{
    private CyclicBarrier c;
    public EmployeeThread(String name,CyclicBarrier c){
        super(name);
        this.c = c;
    }
    @Override
    public void run() {
            System.out.println(Thread.currentThread().getName() + "正在进入会议室……");
        try {
            c.await();//每个线程调用await方法,告诉c我已经到达了屏障,然后当前线程被回收
        } catch (InterruptedException | BrokenBarrierException e) {
            throw new RuntimeException(e);
        }
    }
}

达到一组屏障就触发一个任务执行!达到两组屏障就触发两个任务执行!

Semaphore并发包(*)

  1. 引入:

    1. Semaphore(发信号)的主要作用是控制线程的并发数量
    2. synchronized可以起到"锁"的作用,但某个时间段内,只能有一个线程允许执行。
      Semaphore可以设置同时允许几个线程执行。
    3. Semaphore字面意思是信号量的意思,它的作用是控制访问特定资源的线程数目。
  2. Semaphore的构造器:

    1. public Semaphore(int permits): permits 表示许可线程的数量
    2. public Semaphore(int permits, boolean fair):fair 表示公平性,如果这个设为 true 的话,下次执行的线程会是等待最久的线程
    3. Semaphore的方法:
      public void acquire() throws InterruptedException 表示获取许可
      public void release() release() 表示释放许可
  3. 小结:
    Semaphore可以控制并发线程同时进行的数量。

public class SemaphoreDemo01 {
    public static void main(String[] args) {
        Service service = new Service(); //一个业务,多个线程调用
        for(int i = 1;i <= 5;i ++) //5个线程
        {
            Thread a = new MyThread(service);
            a.start();
        }
    }
}
//线程类跑代码
class MyThread extends Thread{
    private Service service;
    public MyThread(Service service){
        this.service = service;
    }
    @Override
    public void run() {
        service.login();
    }
}
//业务
class Service{
    //表示许可!最多允许1个线程执行acquire()和release()之间的内容
    private Semaphore semaphore = new Semaphore(1); //同时只允许1个进来 控制流量
    //登录功能
    public void login(){
        try {
            semaphore.acquire(); //上锁
            System.out.println(Thread.currentThread().getName()
                    + "进入时间:" + System.currentTimeMillis());
            try {
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + "登录成功!");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName()
                    + "离开时间:" + System.currentTimeMillis());
            semaphore.release(); //开锁
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

Exchanger并发包

  1. 作用

    1. Exchanger(交换者)是一个用于线程间协作的工具类
    2. Exchanger用于进行线程间的数据交换
    3. 这两个线程通过exchange方法交换数据,如果第一个线程先执行exchange()方法,它会一直等待第二个线程也执行exchange方法,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方。
  2. Exchanger构造方法:
    public Exchanger()
    Exchanger重要方法:
    public V exchange(V x)

  3. 分析:
    (1)需要2个线程
    (2)需要一个交换对象负责交换两个线程执行的结果。

  4. 小结:
    Exchanger可以实现线程间的数据交换。
    一个线程如果等不到对方的数据交换就会一直等待。
    我们也可以控制一个线程等待的时间。
    必须双方都进行交换才可以正常进行数据的交换。文章来源地址https://www.toymoban.com/news/detail-605442.html

public class ExchangerDemo01 {
    public static void main(String[] args) {
        Exchanger<String> exchanger = new Exchanger<>();
        new Boy(exchanger).start();
        new Girl(exchanger).start();
    }
}
class Boy extends Thread{
    private Exchanger<String> exchanger;
    public Boy(Exchanger<String> exchanger){
        this.exchanger = exchanger;
    }
    @Override
    public void run() {
        //交换结果
        try {
            System.out.println("男孩开始制作定情信物:心锁");
            String rs = exchanger.exchange("心锁");
            System.out.println("男孩收到了:" + rs);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

class Girl extends Thread{
    private Exchanger<String> exchanger;
    public Girl(Exchanger<String> exchanger){
        this.exchanger = exchanger;
    }
    @Override
    public void run() {
        System.out.println("女孩开始制作定情信物:心匙");
        //交换结果
        try {
            String rs = exchanger.exchange("心匙");
            System.out.println("女孩收到了" + rs);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

时间延时判断

public class ExchangerDemo01 {
    public static void main(String[] args) {
        Exchanger<String> exchanger = new Exchanger<>();
        new Boy(exchanger).start();
        new Girl(exchanger).start();
    }
}
class Boy extends Thread{
    private Exchanger<String> exchanger;
    public Boy(Exchanger<String> exchanger){
        this.exchanger = exchanger;
    }
    @Override
    public void run() {
        //交换结果
        try {
            System.out.println("男孩开始制作定情信物:心锁");
            //等待5秒,对方还不交换就抛出异常
            String rs = exchanger.exchange("心锁",5, TimeUnit.SECONDS);
            System.out.println("男孩收到了:" + rs);
        } catch (InterruptedException | TimeoutException e) {
            throw new RuntimeException(e);
        }
    }
}

class Girl extends Thread{
    private Exchanger<String> exchanger;
    public Girl(Exchanger<String> exchanger){
        this.exchanger = exchanger;
    }
    @Override
    public void run() {
        System.out.println("女孩开始制作定情信物:心匙");
        //交换结果
        try {
            Thread.sleep(6000); //犹豫6秒
            String rs = exchanger.exchange("心匙");
            System.out.println("女孩收到了" + rs);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

到了这里,关于Java_23_并发包的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 身份证阅读器和社保卡读卡器Harmony鸿蒙系统ArkTS语言SDK开发包

    身份证阅读器和社保卡读卡器Harmony鸿蒙系统ArkTS语言SDK开发包

    项目需求,用ArkTS新一代开发语言实现了在Harmony鸿蒙系统上面兼容身份证阅读器和社保卡读卡器,调用了DonseeDeviceLib.har这个读卡库。 需要注意的是,鸿蒙系统的app扩展名为.hap,本项目编译输出的应用为:entry-default-signed.hap 下面是调用身份证阅读器读取身份证信息的接口,支

    2024年02月03日
    浏览(22)
  • Java并发体系-第三阶段-JUC并发包-[2]-CompleableFuture,SynchronousQueue

    Java并发体系-第三阶段-JUC并发包-[2]-CompleableFuture,SynchronousQueue

    java7中引入了一种新的可重复使用的同步屏障,称为移相器Phaser。Phaser拥有与 CyclicBarrier 和 CountDownLatch 类似的功能. 但是这个类提供了更加灵活的应用。CountDownLatch和CyclicBarrier都是只适用于固定数量的参与者。移相器适用于可变数目的屏障,在这个意义上,可以在任何时间注册

    2024年02月07日
    浏览(9)
  • Java语言基础(4)IDEA程序debug断点调试与单元测试junit(图文简单超详细教程,一文搞定debug断点调试和junit单元测试)

    Java语言基础(4)IDEA程序debug断点调试与单元测试junit(图文简单超详细教程,一文搞定debug断点调试和junit单元测试)

    在代码中,找一个位置,点击 前面出现红色点:这个叫 断点 右击鼠标,选择Debug运行 下图:鼠标悬停上面,会提示如下 1、Step Over(F8):点击这个按钮,或者按住F8键,可以往后面执行 2、Step Into(F7):可以进入方法内部,如果当前执行到方法调用,就可以进入方法内部 3、Fo

    2024年02月20日
    浏览(16)
  • 【Design Pattern 23种经典设计模式源码大全】C/Java/Go/JS/Python/TS等不同语言实现

    【Design Pattern 23种经典设计模式源码大全】C/Java/Go/JS/Python/TS等不同语言实现

    经典设计模式源码详解,用不同语言来实现,包括Java/JS/Python/TypeScript/Go等。结合实际场景,充分注释说明,每一行代码都经过检验,确保可靠。 设计模式是一个程序员进阶高级的必然选择,不懂设计模式,就像写文章不懂得层次,盖房子没有结构。只有充分懂得设计之道,

    2023年04月11日
    浏览(13)
  • java语言基础(有c语言基础)

    jdk+记事本编译 编译javac Hello.java 执行java Hello byte b=123;//整型8位最大值是2的7次减一,第一位是符号位 short s=32156;//最大是2的15次-1 int i=101;//31 long l=123;63 float s=3.14; double d=3.14; boolean ok=true; char c=\\\'a\\\'; 3.14默认double 在后面加f float s=3.14f; (F不区分大小写 java无符号 字符 可以赋值

    2024年02月16日
    浏览(14)
  • 【Java基础教程】初识Java

    【Java基础教程】初识Java

    作者简介: 辭七七,目前大一,正在学习C/C++,Java,Python等 作者主页: 七七的个人主页 文章收录专栏 :Java.SE,本专栏主要讲解运算符,程序逻辑控制,方法的使用,数组的使用,类和对象,继承和多态,抽象类和接口等内容 欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖

    2024年02月01日
    浏览(14)
  • 【Java入门合集】第二章Java语言基础(三)

    【Java入门合集】第二章Java语言基础(三)

    博主:命运之光 专栏:Java零基础入门 学习目标 掌握变量、常量、表达式的概念,数据类型及变量的定义方法; 掌握常用运算符的使用; 掌握程序的顺序结构、选择结构和循环结构的使用; 掌握数组的定义及使用方法; 掌握基本的输入输出方法; Java中的语句有很多种形式

    2024年02月03日
    浏览(39)
  • 【Java基础学习打卡08】Java语言跨平台原理

    【Java基础学习打卡08】Java语言跨平台原理

    Java语言编程的一大优势便是跨平台,本文将介绍Java语言是如何实现跨平台的。 计算机高级语言按照程序的执行方式可以分为 编译型语言 和 解释型语言 。 编译型语言: 编写的程序源代码需要通过编译器生成机器语言目标文件,在计算机上直接执行目标文件。编译型语言的

    2024年02月09日
    浏览(9)
  • Java自学第2课:Java语言基础知识要点

    Java自学第2课:Java语言基础知识要点

    任务:创建新项目名为item,包名为number,类名为first。 不指定包时,默认就是工程名,指定后,类文件可以分类了,是这意思吧。包就大概等于一个文件夹。而且在类文件中,有个package声明。这就是包声明。 类的属性就是成员变量,方法中的属性就是局部变量,这个好理解

    2024年02月06日
    浏览(429)
  • 【Java入门合集】第二章Java语言基础(一)

    【Java入门合集】第二章Java语言基础(一)

    博主:命运之光 专栏:Java零基础入门 学习目标 掌握变量、常量、表达式的概念,数据类型及变量的定义方法; 掌握常用运算符的使用; 掌握程序的顺序结构、选择结构和循环结构的使用; 掌握数组的定义及使用方法; 掌握基本的输入输出方法; 提示:不要去强记

    2024年02月02日
    浏览(14)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包