java并发工具包JUC(Java Util Concurrent)

news2024/11/15 23:34:26

1. 什么是JUC

1.1 JUC简介

  • JUC(Java Util Concurrent)是Java中的一个并发工具包,提供了一系列用于多线程编程的类和接口,旨在简化并发编程并提高其效率和可维护性。JUC库包含了许多强大的工具和机制,用于线程管理、同步和协调。

1.2 并发与并行

并发和并行的区别

并发就是多个线程交替执行,速度快的就好像是一起执行一样

并行就是多个线程同时执行  

1.3 进程和线程

1.3.1 进程

  • 指系统中正在运行的一个应用程序的一个实例

1.3.2 线程

  • 一个进程包含多个线程,系统分配处理器时间资源的基本单位,或者说进程内独立执行的一个单元执行流,是程序执行的最小单位

线程的状态

  • Java 中的线程可以处于多种状态,这些状态反映了线程在其生命周期中的不同阶段。以下是 Java 线程可能经历的状态:

  1. NEW(新建)

  • 线程对象已经创建,但尚未启动。

  • 线程还没有调用 start() 方法。

  1. RUNNABLE(可运行)

  • 线程已经启动,并且准备好运行(正在等待 CPU 时间片)。(就绪)

  • 线程可能正在执行(运行中)

  1. BLOCKED(阻塞)

  • 当线程试图获取一个已经由其他线程持有的锁时,它会被阻塞直到锁被释放。

  1. WAITING(等待)

  • 线程处于无限期等待状态,等待其他线程执行特定的动作。

  • 这种状态通常是由调用 Object.wait() 等方法引起的。

  1. TIMED_WAITING(限时等待)

  • 线程处于有限期等待状态,等待其他线程执行特定的动作或等待特定的时间间隔。

  • 这种状态通常是由调用 Thread.sleep(long millis)Object.wait(long timeout)等方法引起的。

  1. TERMINATED [ˈtɜːmɪneɪtɪd](终止)

  • 线程已经执行完毕或因异常而终止。

  • 线程已经完成了它的任务或被强制停止。

wait和sleep的区别

  1. 使用方式

  • wait() 方法属于 Object 类,

  • sleep() 方法属于 Thread 类,是一个静态方法,

  1. 对锁的影响

  • wait() 会释放锁

  • sleep() 不会释放锁,抱着锁睡。

  1. 如何唤醒

  • wait() 方法需要手动唤醒 notify()或notifyAll()

  • sleep() 自己到点了,会自己苏醒

2. java.util.concurrent.locks

2.1 Lock

  • 可中断的锁等待:lockInterruptibly()方法允许等待锁的线程响应中断,而不会像synchronized那样一直等待下去。

  • 尝试非阻塞的获取锁:tryLock()方法尝试获取锁,如果当前锁不可用,立即返回false,不会阻塞线程。

  • 超时获取锁:tryLock(long time, TimeUnit unit)在指定的时间内尝试获取锁,超时后返回false。

2.2 ReentrantLock

2.2.1 主要特点

  1. 可重入:线程可以多次获取同一个锁,而不会导致死锁。

  2. 非阻塞锁尝试:提供了 tryLock 方法,可以在没有立即获得锁时选择返回而不是阻塞。

  3. 锁的公平性和非公平性:可以控制锁的分配策略,决定是否按照请求顺序分配锁。

  4. 条件变量:提供了 Condition 对象,可以用来实现更复杂的同步行为。

2.2.2 公平性和非公平性

  • 构造函数ReentrantLock() 创建一个默认为非公平的锁实例。

  • 构造函数ReentrantLock(boolean fair) 创建一个锁实例,如果 fairtrue 则创建一个公平锁,否则创建一个非公平锁。

  • 公平锁保证锁的获取顺序遵循先进先出(FIFO)的原则,即线程按照请求锁的顺序来获取锁。这意味着一个线程一旦开始等待锁,它将按照其等待时间的先后顺序获得锁。

  • 非公平锁不保证锁的获取顺序,线程在尝试获取锁时可以直接尝试获取,而无需考虑是否有其他线程正在等待。如果获取失败,则线程会进入等待队列。

2.2.3 主要方法

  • lock():获取锁。如果锁已被其他线程持有,则当前线程将阻塞,直到锁可用。

  • tryLock():尝试获取锁。如果锁可用,则获取锁并立即返回 true;如果锁不可用,则立即返回 false

  • tryLock(long time, TimeUnit unit):尝试获取锁,在指定的时间内等待锁,如果在指定时间内未能获取到锁,则返回 false

  • unlock():释放锁。

  • newCondition():创建一个新的 Condition 对象,可以用于 更0\复杂的同步操作。

2.3 ReentrantReadWriteLock

主要特点

  1. 读-写分离:

  • 读锁(ReadLock: 允许多个线程同时获取读锁,只要没有写锁被持有。

  • 写锁(WriteLock: 如果某个线程持有了写锁,则不允许其他线程获取任何类型的锁(读锁或写锁)。

  1. 可重入性:

  • 一个已经持有某种锁的线程可以再次获取同一类型的锁而不会发生死锁。

  • 例如,如果一个线程已经获取了写锁,它可以再次请求写锁而不被阻塞。

  1. 公平性和非公平性:

  • ReentrantReadWriteLock 支持公平和非公平两种模式。

  • 公平模式下,锁的获取顺序遵循请求顺序。

  • 非公平模式下,锁可能优先于队列中的等待线程被授予给新请求。

2.4 Synchronized

  1. synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:

  • 修饰代码块,被修饰的代码块称为同步代码块,作用范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象

public void method() {
    synchronized (this) {
        // 同步代码块
    }
}

Java

  • 修饰方法,被修饰的方法称为同步方法,其作用范围是整个方法,作用对象是调用这个方法的对象

public synchronized void synchronizedMethod() {
    // 方法体
}

Plain Text

  • 对于同步实例方法和同步代码块,锁是当前对象 (this)。对于同步静态方法,锁是当前类的 Class 对象。

2.5 Lock和synchronized的区别

  1. 概念

  • Lock是接口

  • synchronized是关键字

  1. 使用方式

  • synchronized使用在方法或代码块上,会自己解锁

  • Lock需要自己上锁,自己解锁

  1. 锁的力度

  • synchronized不能把控

  • Lock可以把控

  1. 公平性

  • synchronized是非公平锁

  • Lock可以设置它的公平性(默认非公平)

3. java.util.concurrent.atomic

  • java.util.concurrent.atomic提供了原子变量类,这些类支持原子操作,即不可中断的操作。这些类主要用于多线程环境中的高效并发编程,可以避免使用锁带来的性能开销。

3.1 原子变量类

  1. AtomicInteger

  • 主要方法

  • get(): 获取当前值。

  • set(int newValue): 设置当前值。

  • incrementAndGet(): 原子地将当前值加 1 并返回结果。

  • decrementAndGet(): 原子地将当前值减 1 并返回结果。

  • addAndGet(int delta): 原子地将当前值加上指定值并返回结果。

  • getAndIncrement(): 原子地将当前值加 1 并返回原来的值。

  • getAndDecrement(): 原子地将当前值减 1 并返回原来的值。

  • getAndAdd(int delta): 原子地将当前值加上指定值并返回原来的值。

  • compareAndSet(int expect, int update): 如果当前值等于预期值,则原子地将当前值设置为更新值;否则返回 false。

  1. AtomicLong

  • AtomicLongAtomicInteger类似,但处理的是64位的长整型值。

  1. AtomicReference

  • AtomicReference提供了一个引用类型的原子类,它可以存储任何类型的对象。这个类非常有用,因为它可以用来创建复杂的原子数据结构,比如原子队列、栈等。

  1. AtomicBoolean

  • AtomicBoolean是一个布尔型的原子类,提供了线程安全的布尔值更新。

3.2 原子数组

  1. AtomicIntegerArray: 一个整型原子数组。

  2. AtomicLongArray: 一个长整型原子数组。

  3. AtomicReferenceArray<T>: 一个引用类型原子数组。

这些类提供了与原子变量相似的方法,但针对数组元素:

  • get(index): 返回指定索引处的值。

  • compareAndSet(index, expectedValue, newValue): 如果指定索引处的值等于预期值,则以原子方式将其设置为给定的新值。

  • getAndIncrement(index): 以原子方式将指定索引处的值加一并返回旧值。

  • getAndDecrement(index): 以原子方式将指定索引处的值减一并返回旧值。

  • getAndAdd(index, delta): 以原子方式将指定索引处的值加上给定的增量并返回旧值。

  • addAndGet(index, delta): 以原子方式将指定索引处的值加上给定的增量并返回新值

3.3 计数器(LongAdder)

  1. LongAdder 是 Java 8 引入的一个高性能的计数器类,它位于 java.util.concurrent.atomic 包中。LongAdder 主要用于需要频繁更新和读取大量数据的并发场景,它通过使用无锁技术以及基于分段的计数器来实现高性能的原子操作。

  2. 方法

  • add(long x): 原子性地增加指定的值。

  • increment(): 原子性地增加1。

  • decrement(): 原子性地减少1。

  • reset(): 重置计数器。

  • sum(): 获取当前的总和

  1. LongAdder性能比AtomicLong高

4. 辅助类

4.1 CountDownLatch

  • 它允许一个或多个线程等待其他线程完成某些操作。CountDownLatch 类似于一个倒计时计数器,当计数器的值减至零时,所有等待的线程将被释放继续执行。

  • 主要方法

  1. 构造函数CountDownLatch(int count) 创建一个带有指定计数的 CountDownLatch 实例。

  2. countDown():每次调用此方法都会使计数减一。

  3. await():阻塞当前线程,直到计数变为零或超时。

  • await():等待计数变为零。

  • await(long timeout, TimeUnit unit):等待计数变为零,或者达到指定的超时时间。

4.2 CyclicBarrier

  • CyclicBarrier是Java中的一个同步辅助类,它可以让多个线程互相等待,直到所有线程都到达屏障点后才继续执行。需要传入一个整数作为参与线程的数量,当每个线程调用await()方法时,它们都会被阻塞,直到所有线程都调用了await()方法后才会一起继续执行

  • 主要方法

  1. 构造方法

  • CyclicBarrier(int parties): 创建一个新的 CyclicBarrier,参数 parties 指的是需要等待的线程数量。

  • CyclicBarrier(int parties, Runnable barrierAction): 与第一个构造函数类似,但当所有线程都到达屏障时,会有一个额外的 Runnable 任务被执行

  1. 成员方法

  • await():阻塞当前线程,直到所有参与的线程都调用了此方法。

  • reset(): 重置屏障,取消所有正在等待的线程。

  • getParties(): 返回屏障的参与者数量。

  • isBroken(): 返回一个布尔值表示屏障是否已被中断或超时。

4.3 Semaphore

  • 信号量,用于控制同时访问某个资源的线程数量。它的本质是一个“共享锁“。信号量维护了一个信号量许可集。线程可以通过调用 acquire()来获取信号量的许可;当信号量中有可用的许可时,线程能获取该许可;否则线程必须等待,直到有可用的许可为止。 线程可以通过release()来释放它所持有的信号量许可

  • 主要方法

  1. 构造函数

  • Semaphore(int permits):创建一个具有给定数量许可的 Semaphore

  • Semaphore(int permits, boolean fair):创建一个具有给定数量许可的 Semaphore,并且可以选择是否公平分配许可。

  1. 获取许可

  • acquire():等待直到获取一个许可,如果所有许可都被占用,则线程将被阻塞。

  • acquireUninterruptibly():等待直到获取一个许可,即使线程被中断也不会抛出异常。

  • tryAcquire():尝试获取一个许可,如果许可可用则立即返回 true,否则返回 false

  • tryAcquire(long timeout, TimeUnit unit):尝试在给定时间内获取一个许可,如果在超时时间内许可可用则立即返回 true,否则返回 false

  1. 释放许可

  • release():释放一个许可,增加可用的许可数量。

  1. 查询状态

  • availablePermits():返回当前可用的许可数量。

  • getQueueLength():返回等待获取许可的线程数量。

  • hasQueuedThreads():返回是否有线程正在等待获取许可。

  • drainPermits():获取并消耗所有可用的许可。

public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);
​
​
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "running...");
                    sleep(1000);
                    System.out.println(Thread.currentThread().getName() + "end");
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                    semaphore.release();
                }
            }, "线程" + i);
            thread.start();
        }
    }
}

Java

  • 示例代码中创建一个许可量为3的信号量,使用for循环创建10个线程去模拟请求信号量限制的资源,运行代码就会发现,某一时刻最多只有3个线程能访问。

4.4 CountDownLatch,CyclicBarrier,Semaphore的区别

  • CountDownLatch、CyclicBarrier、Semaphore都是Java并发库中的同步辅助类,它们都可以用来协调多个线程之间的执行

  1. CountDownLatch是一个计数器,它允许一个或多个线程等待其他线程完成操作。它通常用来实现一个线程等待其他多个线程完成操作之后再继续执行的操作。

  2. CyclicBarrier是一个同步屏障,它允许多个线程相互等待,直到到达某个公共屏障点,才能继续执行。它通常用来实现多个线程在同一个屏障处等待,然后再一起继续执行的操作。

  3. Semaphore是一个计数信号量,它允许多个线程同时访问共享资源,并通过计数器来控制访问数量。它通常用来实现一个线程需要等待获取一个许可证才能访问共享资源,或者需要释放一个许可证才能完成操作的操作。

  • CountDownLatch适用于一个线程等待多个线程完成操作的情况

  • CyclicBarrier适用于多个线程在同一个屏障处等待

  • Semaphore适用于一个线程需要等待获取许可证才能访问共享

5. ConcurrentHashMap

  • ConcurrentHashMap是Java中一个线程安全的HashMap实现,它被设计用于在多线程环境中高效地存储键值对。ConcurrentHashMap首次出现在Java 5(JDK 1.5)中,并且在Java 8中进行了重大的改进。

  • 在Java 5中,ConcurrentHashMap使用了分段锁(Segmented Locking)的策略来提高并发性能。Java 8中的ConcurrentHashMap放弃了分段锁的策略,转而采用了更简单的CAS(Compare and Swap)+ synchronized的组合方式。这样做的目的是降低锁竞争,并简化实现。

  • 在ConcurrentHashMap中,key和value都不允许为null

主要方法

  • get(key):获取键对应的值。

  • remove(key):删除指定键的映射。

  • containsKey(key):检查是否存在指定的键。

  • forEach(BiConsumer):遍历所有键值对。

  • computeIfAbsent(key, mappingFunction):如果键不存在,则计算并放入新值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2160683.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多比特AI事业部VP程伟光受邀为第四届中国项目经理大会演讲嘉宾

全国项目经理专业人士年度盛会 武汉市多比特信息科技有限公司AI事业部VP程伟光先生受邀为PMO评论主办的全国项目经理专业人士年度盛会——2024第四届中国项目经理大会演讲嘉宾&#xff0c;演讲议题为“AI对于项目经理工作的影响和变化解析”。大会将于10月26-27日在北京举办&am…

如何将Vue项目部署至 nginx

一、准备工作 1.确保安装了开发软件 VS Code&#xff08;此处可查阅安装 VS Code教程&#xff09;&#xff0c;确保相关插件安装成功 2.安装Node.js 和创建Vue项目&#xff08;此处可查阅安装创建教程&#xff09; 3.成功在VS Code运行一个Vue项目&#xff08;此处可查阅运行…

【LeetCode】动态规划—打家劫舍(附完整Python/C++代码)

动态规划—#198. 打家劫舍 前言题目描述基本思路1. 问题定义:2. 理解问题和递推关系:3. 解决方法:4. 进一步优化:5. 小总结: 代码实现Python3代码实现Python 代码解释C代码实现C 代码解释 总结: 前言 在这个问题中&#xff0c;你是一个专业的小偷&#xff0c;计划偷窃沿街的房…

JinDouYun性能测试工具使用方法

1.功能介绍 2. 安卓端支持安卓6及以上的版本&#xff0c;ios支持大部分版本 3. 可以测试游戏&#xff0c;视频&#xff0c;普通应用的性能数据&#xff0c;数据精准&#xff0c;低延迟&#xff0c;无侵入 4.工具下载链接 筋斗云 5.后续功能添加&#xff0c;高版本支持&…

网页爬虫法律与道德:探索法律边界与道德规范

目录 引言 一、网络爬虫技术概述 1.1 定义与功能 1.2 技术原理 1.3 案例分析 二、网络爬虫的法律边界 2.1 合法性要求 2.2 刑事风险 2.3 案例分析 三、网络爬虫的道德规范 3.1 尊重版权和隐私 3.2 合理使用爬虫技术 3.3 透明度和社会责任 四、技术挑战与应对策略…

[linux 驱动]块设备驱动详解与实战

目录 1 描述 2 结构体 2.1 block_device_operations 2.2 gendisk 2.3 block_device 2.4 request_queue 2.5 request 2.6 bio 3.7 blk_mq_tag_set 3.8 blk_mq_ops 3 相关函数 3.1 注册注销块设备 3.1.1 register_blkdev 3.1.2 unregister_blkdev 3.2 gendisk 结构…

SpringBoot开发——整合Hutool工具类轻松生成验证码

文章目录 1、Hutool简介2、验证码效果展示2.1 扭曲干扰验证码2.2 线条干扰验证码2.3 圆圈干扰验证码3、验证码应用场景3.1. 用户注册与身份验证3.2. 支付验证3.3. 订单与物流通知3.4. 信息安全与隐私保护3.5. 通知与提醒3.6. 其他应用场景4、Hutool工具类实现验证码生成4.1 引入…

如何使用ssm实现基于VUE的儿童教育网站的设计与实现+vue

TOC ssm676基于VUE的儿童教育网站的设计与实现vue 第一章 课题背景及研究内容 1.1 课题背景 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安全…

API公共开放平台设计

背景 随着业务发展未来会有更多的三方应用接入公司平台,目前为服务商定制的机制无法满足三方应用快速接入,所以需要一个更加通用的解决方案,开放平台势在必行。 目标 设计一套通用协议,可以支持其他应用快速接入。 说明 本方案旨在设计整体架构,以及对为何这样设计做…

React 理解 re-render 的作用、概念,并提供详细的例子解释

一、什么是 re-render 在 React 中 re-render&#xff08;重新渲染&#xff09; 是经常发生的行为&#xff0c;主要确保视图要时刻保持最新的数据来呈现。 但每次发生 re-render 也是有代价的&#xff0c;比如数据状态、focus 焦点、表单数据、都得重置&#xff0c; 遇到代码…

获取商品销量详情API:深入解析返回值,助力电商决策

在电商行业&#xff0c;了解商品的销量详情对于商家制定营销策略、优化库存管理和提升用户体验至关重要。通过调用获取商品销量详情的API接口&#xff0c;商家可以实时获取关键的销售数据&#xff0c;从而做出更加明智的决策。本文将深入解析获取商品销量详情API的返回值&#…

linux信号| 学习信号三步走 | 学习信号需要打通哪些知识脉络?

前言: 本节内容主要讲解linux下信号的预备知识以及信号的概念&#xff0c; 信号部分我们将会分为几个阶段进行讲解&#xff1a;信号的概念&#xff0c; 信号的产生&#xff0c; 信号的保存。本节主要讲解信号 ps:本节内容适合学习了进程相关概念的友友们进行观看哦 目录 什么是…

轻松重置 MySQL 8.0 Root 密码的简便方法!

在Windows环境下安装MySQL数据后&#xff0c;如果忘记了 MySQL 8.0 的 root 密码&#xff0c;不必担心&#xff01;通过 --skip-grant-tables 和 named-pipe 模式登录后&#xff0c;只需几步简单的 SQL 命令即可重置密码&#xff1a;刷新权限表、修改密码、再刷新权限&#xff…

SpringBoot+Thymeleaf租房管理系统

> 这是一个基于SpringBootThymeleafBootstrap实现的租房管理系统。 > 功能比较完善&#xff0c;包括用户注册/登录、房源登记、账单费用配置、统计报告等功能。 > 模拟真实使用环境&#xff0c;包括了自然人与法人的身份证明录入、房产证信息录入、通过邮件推送月…

E2VPT: An Effective and Efficient Approach for Visual Prompt Tuning

论文汇总 存在的问题 1.以前的提示微调方法那样只关注修改输入&#xff0c;而应该明确地研究在微调过程中改进自注意机制的潜力&#xff0c;并探索参数效率的极限。 2.探索参数效率的极值来减少可调参数的数量? 解决办法 提示嵌入进行transformer中 提示剪枝 Token-wise …

学生网上选课系统设计与实现

学生网上选课系统设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装学生网上选课系统软件来发挥其…

托盘检测系统源码分享

托盘检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vision …

两数之和、三数之和、四数之和

目录 两数之和 题目链接 题目描述 思路分析 代码实现 三数之和 题目链接 题目描述 思路分析 代码实现 四数之和 题目链接 题目描述 思路分析 代码实现 两数之和 题目链接 LCR 179. 查找总价格为目标值的两个商品 - 力扣&#xff08;LeetCode&#xff09; 题目…

牛客周赛 Round 61 (C++实现)

比赛链接&#xff1a;牛客竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com) 文章目录 1.致十年后的我们1.1 题目描述1.2 思路1.3 代码 2.简单图形问题2.1 题目描述2.2 思路2.3 代码 3. 小红的机器人构造3.1 题目描述3.2 思路3.2.1 问题13.2.2 问题23…

力扣 中等 1901.寻找峰值II

文章目录 题目介绍题解 题目介绍 题解 需要明白一个事实&#xff1a;从任意一个点出发&#xff0c;可以经过一个递增路径&#xff0c;找到一个极大值点。 求出一行的最大值&#xff0c;如果这行最大值比上面的要小&#xff0c;那峰值&#xff08;之一&#xff09;就会在上面 …