前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >8-并发包

8-并发包

作者头像
Ywrby
发布于 2022-10-27 05:24:02
发布于 2022-10-27 05:24:02
75200
代码可运行
举报
文章被收录于专栏:YwrbyYwrby
运行总次数:0
代码可运行

并发包

概念

在实际开发中不考虑线程安全的情况下,一般不需要做线程安全处理,防止过多的处理导致性能变差

但是开发中有很多业务需要考虑线程安全的相关问题,此时就必须考虑线程安全的处理

Java为很多业务场景提供了性能优异,且线程安全的并发包

ConcurrentHashMap

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package ConcurrentHashMap;

import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class CHMDemo1 {

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

    public static void main(String[] args) {
        Runnable target = new CHMRunnable();
        Thread t1 = new Thread(target);
        Thread t2 = new Thread(target);
        t1.start();
        t2.start();


        /*
        * 注意:首先这里不可以直接简化用new Thread(target).start();开启线程
        * 两个线程必须实例化对象,这是由于后续要用到join()方法
        * join方法的作用在于避免主线程和t1,t2两个线程争抢CPU
        * 使用join方法后,在t1,t2执行完之前,后续主线程都不会执行
        * 这就避免了提前打出maps长度导致结果并不是最终运行的结果
        * 同时t1,t2都用到了join方法,所以二者之间仍然是并发执行
        * */
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("maps长度="+maps.size());
        /*
        * 可以看到,当使用hashmap类型时,最终的执行结果并不是1000000
        * 这是由于单纯通过hashmap算法可能出现两个线程同时插入到同一线程的情况
        * HashMap时线程不安全的,性能好
        *
        * 可以看到,当使用hashtable类型时,最终执行结果始终都是1000000
        * 可见hashtable保证了线程的安全性,但是这种方式效率极低,在项目中基本被舍弃
        * 因为它的实现方式在每个方法中都加上了锁
        * HashTable时线程安全的,性能较差
        *
        * ConcurrentHashMap的实现与hashtable不同,它只锁住对应变量的桶(分段式锁)
        * 所以其他变量的增删改不会相互影响,效率得到了极大的保证
        * 保证了线程安全,综合性能较好
        * */
    }
}


class CHMRunnable implements Runnable{

    @Override
    public void run() {
        for(int i=0;i<500000;i++){
            CHMDemo1.maps.put(Thread.currentThread().getName()+i,Thread.currentThread().getName()+i);
        }
    }
}

CountDownLatch

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

e.g. 线程1执行A任务和C任务,线程2执行B任务,且根据规定必须按照A,B,C的顺序执行任务:

所以就可以利用CountDownLatch保证在线程1执行完任务A后等待线程2执行完毕再执行剩余任务

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package ConcurrentHashMap;

//CountDownLatch

import java.util.concurrent.CountDownLatch;

public class CDLDemo {
    public static void main(String[] args) {
        //创建CountDownLatch对象,用于监督1,2线程的执行情况
        //这里传入的参数是步数,表示唤醒线程需要的步数,部署为0时,等待的线程开始执行
        //这种方法比线程通信更加灵活
        CountDownLatch c=new CountDownLatch(1);
        new Thread_first(c).start();
        new Thread_second(c).start();
    }
}

class Thread_first extends Thread{
    private CountDownLatch c;
    public Thread_first(CountDownLatch c) {
        this.c=c;

    }

    @Override
    public void run() {
        System.out.println("A");
        //等待状态,让当前线程让出CPU等待
        try {
            c.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("C");
    }
}

class Thread_second extends Thread{
    private CountDownLatch c;
    public Thread_second(CountDownLatch c) {
        this.c=c;

    }

    @Override
    public void run() {
        System.out.println("B");
        c.countDown();  //让计数器减一,当计数器为0时唤醒等待的线程
    }
}

可以看到,在使用countdownlatch之前,最终结果是ACB,使用countdownlatch之后,最终结果是ABC

CyclicBarrier

某个线程任务必须等待其他线程执行完毕以后才能最终触发自己执行

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package ConcurrentHashMap;

//CyclicBarrier

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

public class CBDemo {
    public static void main(String[] args) {
        //创建任务循环屏障对象,等到5个线程全部执行完毕之后触发一次任务
        // 第一个参数表示等待线程执行的个数,第二个参数表示执行的任务
        CyclicBarrier c=new CyclicBarrier(5,new CBRunnable());
        for (int i = 0; i < 5; i++) {
            new CBThread("用户"+i,c).start();
        }

    }
}

class CBRunnable implements Runnable{

    @Override
    public void run() {
        System.out.println("五个任务全部执行完毕,"+Thread.currentThread().getName()+"开始执行!");
    }
}

class CBThread extends Thread{
    private CyclicBarrier c;
    public CBThread(String s,CyclicBarrier c) {
        super(s);
        this.c=c;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"正在执行!");
            c.await();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
运行结果
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
用户3正在执行!
用户1正在执行!
用户2正在执行!
用户0正在执行!
用户4正在执行!
五个任务全部执行完毕,用户3开始执行!

当修改代码中的for循环为10次时,可以看到最终运行结果为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
用户4正在执行!
用户6正在执行!
用户1正在执行!
用户5正在执行!
用户3正在执行!
用户2正在执行!
用户8正在执行!
用户7正在执行!
用户0正在执行!
用户9正在执行!
五个任务全部执行完毕,用户7开始执行!
五个任务全部执行完毕,用户9开始执行!

可以看到每个线程调用await()方法告诉c自己已经运行完成,然后当前线程被回收(注意,不是被销毁,如果是销毁则后续c执行传入的任务时获取当前线程得到的必然不是这些已经完成命名的线程),并且循环屏障是达到一组屏障就触发一次任务的执行,而不一定只执行一次

Semaphore

主要作用是控制线程的并发数量,synchronized可以起到“锁”的作用,保证在某个时间段内,只允许一个线程访问,而Seamaphore则可以设置同时允许几个线程进行。

Semaphore字面意思是信号量的意思,作用就是控制某段时间内访问特定资源的线程数目

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package ConcurrentHashMap;

import java.util.concurrent.Semaphore;

public class SemaphoreDemo {
    public static void main(String[] args) {
        SemaTask task=new SemaTask();
        for (int i = 0; i < 10; i++) {
            new SemaThread(task).start();
        }

    }
}


//任务代码
class SemaTask{
    //创建Semaphore对象,第一个参数表示允许执行acquire和release之间内容的线程数量
    private Semaphore sema=new Semaphore(2);
    public void task(){
        try {
            sema.acquire();
            System.out.println(Thread.currentThread().getName()+"进入时间:"+System.currentTimeMillis());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"离开时间:"+System.currentTimeMillis());
            sema.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class SemaThread extends Thread{
    private SemaTask task;
    public SemaThread(SemaTask task){
        this.task=task;
    }
    @Override
    public void run() {
        task.task();
    }
}

Exchanger

一个用于线程间协作的工具类,Exchanger用于线程间的数据交换。

两个线程通过exchanger方法交换数据,如果第一个线程先执行exchanger方法,它会一直等待第二个线程也执行exchanger方法,当两个线程都达到同步点时(程序执行完毕),这两个线程就可以进行数据交换,将本线程生产出来的数据传递给对方

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package ConcurrentHashMap;

import java.util.concurrent.Exchanger;

public class ExchangerDemo {
    public static void main(String[] args) {
        //创建Exchanger交换数据
        Exchanger<String> exch=new Exchanger<String>();
        Thread t1=new task("task1",exch,"你好,我是task1");
        Thread t2=new task("task2",exch,"你好,我是task2");
        t1.start();
        t2.start();
    }
}

class task extends Thread{
    private Exchanger<String> exch;
    private String result;
    public task(String name,Exchanger exch,String result){
        super(name);
        this.exch=exch;
        this.result=result;
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"正在执行工作流程");
        //交换结果
        try {
            String s=exch.exchange(result);
            System.out.println(Thread.currentThread().getName()+"收到交换信息“"+s+"”");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
运行结果
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
task2正在执行工作流程
task1正在执行工作流程
task2收到交换信息“你好,我是task1”
task1收到交换信息“你好,我是task2”
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-03-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Java学习笔记(并发包介绍)
在实际开发中如果不需要考虑线程安全问题,大家不需要做线程安全,因为如果做了反而性能不好!但是开发中有很多业务是需要考虑线程安全问题的,此时就必须考虑了。否则业务出现问题。Java为很多业务场景提供了性能优异,且线程安全的并发包,程序员可以选择使用!
用户5513909
2023/04/25
2790
Java学习笔记(并发包介绍)
杰哥教你面试之一百问系列:java中高级多线程concurrent的使用
提到多线程,当然要熟悉java提供的各种多线程相关的并发包了,而java.util.concurrent就是最最经常会使用到的,那么关于concurrent的面试题目有哪些呢?一起来看看吧。
程序那些事
2023/09/07
3940
Java并发工具那些事儿
Java并发工具类主要有CyclicBarrier、CountDownLatch、Semaphore和Exchanger,日常开发中经常使用的是CountDownLatch和Semaphore。下面就简单分析下这几个并发工具类:
luoxn28
2020/03/11
4330
Java多线程06——JUC并发包02
​​CountDownLatch​​ 同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
头发还在
2023/10/16
1840
Java多线程06——JUC并发包02
Java并发编程系列-(2) 线程的并发工具类
JDK 7中引入了fork-join框架,专门来解决计算密集型的任务。可以将一个大任务,拆分成若干个小任务,如下图所示:
码老思
2023/10/19
2310
Java并发编程系列-(2) 线程的并发工具类
AQS、CountDownLatch、CyclicBarrier、Semaphore、Exchanger
在编程的竞技场中,多线程与并发是每一级大牛必备的技能!今天,就让我们深入了解Java并发武器库中的“五神兵”——AQS、CountDownLatch、CyclicBarrier、Semaphore、Exchanger的强大之处。他们如棋盘上的棋子,既能彼此协调,又能独当一面,解决了无数线程之问的冲突、同步与协作难题。
疯狂的KK
2024/06/04
1390
AQS、CountDownLatch、CyclicBarrier、Semaphore、Exchanger
彻底理解Java并发:Java并发工具类
CountDownLatch 线程计数器,俗称闭锁,作用是类似加强版的 Join,是让一组线程等待其他的线程完成工作以后才执行
栗筝i
2022/12/01
5560
Java高并发必学--concurrent包
JDK1.5引入了java.util.concurrent包,里边很有多有用的组件,我们挑选一些来学习
用户7353950
2022/06/23
4930
java并发编程(五)
阻塞队列:在某些情况下,会挂起线程,一旦条件满足,被挂起的线程会自动唤醒。而阻塞队列无需关心什么时候阻塞,什么时候唤醒。
疯狂的KK
2020/03/25
3010
多线程进阶--JUC并发编程
https://blog.csdn.net/weixin_44502509/article/details/106872957
hhss
2021/02/12
6310
多线程进阶--JUC并发编程
​Java 并发包提供了哪些并发工具类
假设有10个人排队,我们将其分成5个人一批,使用CountDownLatc 来协调。
王小明_HIT
2020/05/08
1.2K0
​Java 并发包提供了哪些并发工具类
并发工具箱 concurrent包的原理分析以及使用
BlockingQueue 通常用于一个线程生产对象,而另外一个线程消费这些对象的场景。下图是对这个原理的阐述:
小勇DW3
2018/08/30
8330
并发工具箱 concurrent包的原理分析以及使用
JDK提供的并发工具类
await(),进入等待的状态 countDown(),计数器减一 应用场景:启动三个线程计算,需要对结果进行累加。
Dream城堡
2019/05/21
3850
java一些常用并发工具示例
最近把《java并发编程实战》-Java Consurrency in Practice 重温了一遍,把书中提到的一些常用工具记录于此: 一、闭锁(门栓)- CountDownLatch 适用场景:多线程测试时,通常为了精确计时,要求所有线程都ready后,才开始执行,防止有线程先起跑,造成不公平,类似的,所有线程执行完,整个程序才算运行完成。 /** * 闭锁测试(菩提树下的杨过 http://yjmyzz.cnblogs.com/) * * @throws Inte
菩提树下的杨过
2018/01/18
5790
JUC 中 4 个常用的并发工具类
CountDownLatch是我目前使用比较多的类,CountDownLatch初始化时会给定一个计数,然后每次调用countDown() 计数减1,
张乘辉
2021/11/10
3840
JUC 常用4大并发工具类
JUC就是java.util.concurrent包,这个包俗称JUC,里面都是解决并发问题的一些东西
彼岸舞
2020/11/06
5340
【死磕Java并发】常用并发工具类详解
在前几篇文章中,我们讲到了线程、线程池、BlockingQueue 等核心组件,其实 JDK 给开发者还提供了比synchronized更加高级的线程同步组件,比如 CountDownLatch、CyclicBarrier、Semaphore、Exchanger 等并发工具类。
Java极客技术
2023/12/13
6330
【死磕Java并发】常用并发工具类详解
java架构之路(多线程)JUC并发编程之Semaphore信号量、CountDownLatch、CyclicBarrier栅栏、Executors线程池
  上次博客我们主要说了我们juc并发包下面的ReetrantLock的一些简单使用和底层的原理,是如何实现公平锁、非公平锁的。内部的双向链表到底是什么意思,prev和next到底是什么,为什么要引入heap和tail来值向null的Node节点。高并发时候是如何保证state来记录重入锁的,在我们的上次博客都做了详细的说明。这次我们来聊一些简单易懂且实用的AQS中的工具类。
小菜的不能再菜
2020/02/24
4390
线程同步辅助工具类
Java 并发编程是整个 Java 开发体系中最难以理解但也是最重要的知识点,也是各类开源分布式框架(如 ZooKeeper、Kafka、Spring Cloud、Netty 等)中各个并发组件实现的基础。J.U.C 并发包,即 java.util.concurrent 包,大大提高了并发性能,是 JDK 的核心工具包,是 JDK 1.5 之后,由 Doug Lea 实现并引入。而 AQS 被认为是 J.U.C 的核心。
BUG弄潮儿
2021/03/22
7890
Java 实现多线程的n种方法
在现代编程中,多线程是一项关键技术,它使得程序能够同时执行多个任务,提高了系统的效率和性能。在Java中,有多种方法可以实现多线程,每种方法都有其独特的应用场景和优缺点。本文将详细介绍几种常见的Java多线程实现方法,包括基础的Thread类、Runnable接口、高级的线程池、并发工具类、异步编程以及新的并发特性,帮助你深入理解多线程的不同实现方式。
繁依Fanyi
2024/11/22
2020
推荐阅读
相关推荐
Java学习笔记(并发包介绍)
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文