Java并发编程
文章平均质量分 64
JUC -- 黑马
CodeJiao
今之视昔,亦如后世视今。
展开
-
Java中的锁机制 -- 乐观锁、悲观锁、自旋锁、可重入锁、读写锁、公平锁、非公平锁、共享锁、独占锁、重量级锁、轻量级锁、偏向锁、分段锁、互斥锁、同步锁、死锁、锁粗化、锁消除
乐观锁是一种乐观思想,假定当前环境是读多写少,遇到并发写的概率比较低,读数据时认为别的线程不会正在进行修改(所以没有上锁)。写数据时,判断当前与期望 值是否相同,如果相同则进行更新(更新期间加锁,保证是原子性的)。Java中的乐观锁:CAS(Compare And Set),比较并替换,比较当前值(主内存中的值),与预期值(当前线程中的值,主内存中值的一份拷贝)是否一样,一样则更新,否则继续进行CAS操作。如上图所示,乐观锁可以同时进行读操作,读的时候其他线程不能进行写操作。悲观锁是一种悲观思想,即认为写多原创 2022-04-12 15:52:33 · 2305 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 JUC ConcurrentHashMap -- ConcurrentHashMap的错误使用和正确使用(示例:统计单词个数)
1. 练习: 单词计数1.1 错误使用1.1.1 生成测试数据package com.tian;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.util.ArrayList;import java.util.Collections;import java.util.Li原创 2021-10-08 00:39:24 · 253 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 JUC 线程安全的集合类 -- 线程安全的集合类概述
1. 线程安全的集合类概述1.1 遗留的线程安全集合出现时间比较早,线程安全的方法上面都是使用synchronized修饰,并发的性能比较低。时至今日不推荐使用。示例:1.2 使用 Collections 装饰的线程安全集合在原来线程不安全的集合里面的方法多加了一个synchronized修饰,使得原来线程不安全的方法变得线程安全。所以该类在性能上相比较于遗留的线程安全集合并没有提升。使用 Collections 装饰的线程安全集合,如:Collections.synchro原创 2021-10-07 23:42:25 · 366 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 JUC CyclicBarrier(循环栅栏 与CountdownLatch最大的不同是可以重值倒计时) -- CyclicBarrier介绍、使用、注意事项
1. CyclicBarrier介绍循环栅栏,用来进行线程协作,等待线程满足某个计数。构造时设置『计数个数』,每个线程执行到某个需要“同步”的时刻调用 await() 方法进行等待,当等待的线程数满足『计数个数』时,继续执行。与CountdownLatch最大的不同是可以重值倒计时CountDownLatch问题说明: CountDownLatch想要重置倒计时就只有重新创建一个新的对象private static void test1() { ExecutorService se原创 2021-10-07 23:16:34 · 255 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 JUC CountdownLatch(倒计时锁) -- CountdownLatch应用(等待多个线程准备完毕(\r可以覆盖上次的打印内)、等待多个远程调用结束)
1. 等待多个线程准备完毕(\r可以覆盖上次的打印内)玩王者荣耀时,有十个玩家(相当于十个线程),只有等这十个玩家的进度条都为100%时才会开始游戏,现在我们使用CountdownLarch倒计时锁模拟这个过程示例代码:package com.tian;import lombok.extern.slf4j.Slf4j;import java.util.Arrays;import java.util.Random;import java.util.concurrent.CountDown原创 2021-10-05 17:27:10 · 218 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 JUC CountdownLatch(倒计时锁) -- CountdownLatch(使用、CountdownLatch原理、改进: 配合线程池使用)
1. CountdownLatch用来进行线程同步协作,等待所有线程完成倒计时。其中构造参数用来初始化等待计数值,await() 用来等待计数归零,countDown() 用来让计数减一1.1 使用示例代码:package com.tian;import lombok.extern.slf4j.Slf4j;import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutionExcepti原创 2021-10-05 16:47:37 · 245 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 JUC ReentrantLock -- ReentrantLock原理
1. ReentrantLock原理1.1 非公平锁实现原理加锁解锁流程先从构造器开始看,默认为非公平锁实现:public ReentrantLock() { sync = new NonfairSync();}NonfairSync 继承自 AQS 没有竞争时第一个竞争出现时:Thread-1 执行了CAS 尝试将 state 由 0 改为 1,结果失败进入 tryAcquire 逻辑,这时 state 已经是1,结果仍然失败接下来进入 addWaite原创 2021-10-05 11:19:07 · 223 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 JUC Semaphore(信号量) -- Semaphore原理
1. Semaphore原理Semaphore 有点像一个停车场,permits 就好像停车位数量,当线程获得了 permits 就像是获得了停车位,然后停车场显示空余车位减一。刚开始permits(state)为 3,这时 5 个线程来获取资源假设其中 Thread-1,Thread-2,Thread-4 cas 竞争成功,而 Thread-0 和 Thread-3 竞争失败,进入 AQS 队列 park 阻塞这时 Thread-4 释放了 permits,状态如下接下来 Thread-0原创 2021-10-05 10:06:04 · 210 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 JUC Semaphore(信号量)-- 限制对共享资源的使用 改进数据库连接池
1. 限制对共享资源的使用 改进数据库连接池使用 Semaphore 限流,在访问高峰期时,让请求线程阻塞,高峰期过去再释放许可,当然它只适合限制单机线程数量,并且仅是限制线程数,而不是限制资源数。用 Semaphore 实现简单连接池,对比『享元模式』下的实现(用wait notify),性能和可读性显然更好,注意下面的实现中线程数和数据库连接数是相等的示例代码:package com.tian;import lombok.extern.slf4j.Slf4j;import jav原创 2021-10-05 09:48:16 · 194 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 JUC Semaphore(信号量) -- 介绍 & 使用
1. Semaphore1.1 介绍信号量,用来限制能同时访问共享资源的线程上限。作用类似于停车场里面的信号指示牌: 显示还有多少空车位。1.2 使用1.2.1 不使用 Semaphorepackage com.tian;import lombok.extern.slf4j.Slf4j;@Slf4j(topic = "c.TestSemaphore")public class TestSemaphore { public static void main(String[]原创 2021-10-05 00:47:22 · 379 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 JUC 读写锁 StampedLock -- 介绍 & 使用
1. StampedLock1.1 介绍该类自 JDK 8 加入,是为了进一步优化读性能,它的特点是在使用读锁、写锁时都必须配合【戳】使用加解读锁:long stamp = lock.readLock();lock.unlockRead(stamp);加解写锁:long stamp = lock.writeLock();lock.unlockWrite(stamp);乐观读,StampedLock 支持 tryOptimisticRead() 方法(乐观读),读取完毕后需要做原创 2021-10-05 00:29:45 · 240 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 JUC 读写锁 ReentrantReadWriteLock -- ReentrantReadWriteLock(不可重入锁)使用 & 注意事项
1. 非公平锁实现原理原创 2021-10-04 21:41:11 · 376 阅读 · 0 评论 -
JUC并发编程 JUC AQS原理 -- AQS概述 & 实现不可重入锁
1. AQS原理1.1 概述全称是 AbstractQueuedSynchronizer,是阻塞式锁和相关的同步器工具的框架特点:用 state 属性来表示资源的状态(分独占模式和共享模式),子类需要定义如何维护这个状态,控制如何获取锁和释放锁:getState - 获取 state 状态setState - 设置 state 状态compareAndSetState - cas 机制设置 state 状态独占模式是只有一个线程能够访问资源,而共享模式可以允许多个线程访问资源原创 2021-10-04 19:52:12 · 240 阅读 · 0 评论 -
JUC并发编程 概览 进程与线程-- JUC介绍 & 线程/进程 & 并发/并行 & Java代码查看CPU的核数
1. JUC介绍JUC就是java.util .concurrent工具包的简称。这是一个处理线程的工具包。2. 线程/进程进程:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。线程:通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义,线程可以利用进程所有拥有的资源。在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把原创 2021-08-16 22:07:34 · 417 阅读 · 1 评论 -
JUC并发编程 共享模式之工具 线程池 -- Fork / Join 框架(JDK1.7 新加入的线程池实现)
1. Fork / Join 框架1.1 介绍Fork/Join 是 JDK 1.7 加入的新的线程池实现,它体现的是一种分治思想,适用于能够进行任务拆分的 cpu 密集型运算所谓的任务拆分,是将一个大任务拆分为算法上相同的小任务,直至不能拆分可以直接求解。跟递归相关的一些计算,如归并排序、斐波那契数列、都可以用分治思想进行求解Fork/Join 在分治的基础上加入了多线程,可以把每个任务的分解和合并交给不同的线程来完成,进一步提升了运算效率Fork/Join 默认会创建与 cpu 核心数大原创 2021-10-03 00:42:20 · 226 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 ThreadPoolExecutor -- 线程池应用之定时任务(在每周周四执行定时任务)
1. 线程池应用之定时任务示例: 在每周周四执行定时任务package com.tian;import java.time.DayOfWeek;import java.time.Duration;import java.time.LocalDateTime;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurre原创 2021-10-03 00:06:48 · 513 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 ThreadPoolExecutor -- 正确处理线程池异常
1. 正确处理线程池异常1.1 如果不处理异常示例代码:package com.tian;import lombok.extern.slf4j.Slf4j;import java.util.concurrent.ExecutionException;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent原创 2021-10-02 21:05:27 · 384 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 ThreadPoolExecutor -- 任务调度线程池 定时任务 / 延时执行(ScheduledThreadPoolExecutor 延时执行 / 定时执行)
1. 任务调度线程池1.1 ScheduledThreadPoolExecutor 延时执行示例代码(任务都延时1s执行):package com.tian;import java.util.Date;import java.util.concurrent.ExecutionException;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;impor原创 2021-10-02 20:38:46 · 1074 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 ThreadPoolExecutor -- 任务调度线程池 定时任务 / 延时执行(Timer的缺点)
1. 任务调度线程池1.1 Timer的缺点在『任务调度线程池』功能加入之前,可以使用 java.util.Timer 来实现定时功能,Timer 的优点在于简单易用,但由于所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任务。1.1.1 正常情况示例代码:package com.tian;import lombok.extern.slf4j.Slf4j;import java.util.Timer;原创 2021-10-02 20:30:11 · 379 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 ThreadPoolExecutor 多线程设计模式 -- 异步模式之工作线程(定义、饥饿 & 解决饥饿 & 线程池创建多少线程数目合适)
1. 工作线程1.1 定义让有限的工作线程(Worker Thread)来轮流异步处理无限多的任务。也可以将其归类为分工模式,它的典型实现就是线程池,也体现了经典设计模式中的享元模式例如:海底捞的服务员(线程),轮流处理每位客人的点餐(任务),如果为每位客人都配一名专属的服务员,那么成本就太高了(对比另一种多线程设计模式:Thread-Per-Message(为每一个任务新分配一个线程,由这个线程来执行处理。))注意,不同任务类型应该使用不同的线程池,这样能够避免饥饿,并能提升效率例如原创 2021-10-02 19:37:01 · 259 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 线程池 JDK 提供的线程池工具类 -- ThreadPoolExecutor(关闭线程池: shutdown、shutdownNow)
1. 关闭线程池1.1 shutdown/*线程池状态变为 SHUTDOWN- 不会接收新任务- 但已提交任务会执行完- 此方法不会阻塞调用线程的执行*/void shutdown();测试代码:package com.tian;import lombok.extern.slf4j.Slf4j;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorServic原创 2021-10-02 17:45:09 · 211 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 线程池 JDK 提供的线程池工具类 -- ThreadPoolExecutor(提交任务: submit、execute 、invokAll、invokeAny)
1. ThreadPoolExecutor 提交任务// 执行任务void execute(Runnable command);// 提交任务 task,用返回值 Future 获得任务执行结果<T> Future<T> submit(Callable<T> task);// 提交 tasks 中所有任务<T> List<Future<T>> invokeAll(Collection<? extends Callabl原创 2021-10-02 17:07:44 · 332 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 线程池 JDK 提供的线程池工具类 -- Executors 类创建线程池(创建ThreadPoolExecutor对象)
1. Executors 类创建线程池ThreadPoolExecutor类构造方法:public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler h原创 2021-10-02 15:53:25 · 266 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 线程池 JDK 提供的线程池工具类 -- ThreadPoolExecutor(线程池状态、构造方法)
1. ThreadPoolExecutor类图:1.1 线程池状态ThreadPoolExecutor 使用 int 的高 3 位来表示线程池状态,低 29 位表示线程数量从数字上比较,TERMINATED > TIDYING > STOP > SHUTDOWN > RUNNING(因为是高三位,所以第一位代表符号位(0正1负))这些信息存储在一个原子变量 ctl 中,目的是将线程池状态与线程个数合二为一,这样就可以用一次 cas 原子操作进行赋值1.2原创 2021-10-02 14:37:15 · 193 阅读 · 0 评论 -
JUC并发编程 共享模式之工具 线程池 -- 自定义线程池(阻塞队列)
1. 自定义线程池(阻塞队列)1.1 线程池介绍产生背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大。解决思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具。1.2 线程池(阻塞队列)图示:1.3 自定义线程池(阻塞队列)package com.tian;import lombok.extern.slf4j.Slf4j;import java.util.Ar原创 2021-10-02 13:52:48 · 397 阅读 · 0 评论 -
JUC并发编程 共享模型之不可变 不可变设计 -- final关键字原理 & ASM Bytecode Outline 插件查看Java字节码 & 无状态
final关键字原理原创 2021-09-16 00:18:54 · 242 阅读 · 0 评论 -
JUC并发编程 共享模型之不可变 不可变设计 -- 享元模式(定义和体现 & 自定义连接池)
1. 定义和体现1.1 定义享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。1.2 体现在JDK中 Boolean,Byte,Short,Integer,Long,Character 等包装类提供了 valueOf 方法,例如 Long 的valueOf 会缓存 -128~127 之间的 L原创 2021-09-15 00:49:45 · 189 阅读 · 0 评论 -
JUC并发编程 共享模型之不可变 -- 日期转换的问题(SimpleDateFormat ) & 不可变对象使用和设计 & 保护性拷贝
1. 日期转换的问题问题提出:下面的代码在运行时,由于 SimpleDateFormat 不是线程安全的,有很大几率出现 java.lang.NumberFormatException 或者出现不正确的日期解析结果,例如:@Slf4j(topic = "c.Test1")public class Test1 { public static void main(String[] args) { SimpleDateFormat sdf = new SimpleDateFor原创 2021-09-08 22:01:09 · 204 阅读 · 1 评论 -
JUC并发编程 共享模式之无锁 -- 原子数组 & 原子更新器(字段更新器) & 原子累加器(LongAdder)
1. 原子数组有的时候我们不需要修改引用本身,我们要修改的是里面的内容,这时就需要用到原子数组。原子数组:AtomicIntegerArrayAtomicLongArrayAtomicReferenceArray示例代码:package tian;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import java.util.concurrent.atomic.Atomic原创 2021-09-08 16:01:21 · 241 阅读 · 1 评论 -
JUC并发编程 共享模式之无锁 -- 原子整数(AtomicInteger)& 原子引用 (介绍 & ABA问题 & AtomicStampedReference...))
1. 原子整数(AtomicInteger)J.U.C 并发包提供了:AtomicBooleanAtomicIntegerAtomicLong以 AtomicInteger 为例:AtomicInteger i = new AtomicInteger(0);// 获取并自增(i = 0, 结果 i = 1, 返回 0),类似于 i++System.out.println(i.getAndIncrement());// 自增并获取(i = 1, 结果 i = 2, 返回 2),类原创 2021-09-08 15:40:41 · 334 阅读 · 2 评论 -
JUC并发编程 共享模式之无锁 -- CAS(工作方式 & 与volatile的关联 & 效率分析 & 特点(乐观锁/悲观锁))
1. 工作方式前面看到的 AtomicInteger 的解决方法,内部并没有用锁来保护共享变量的线程安全。那么它是如何实现的呢? @Override public void withdraw(Integer amount) { while (true) { // 获取余额的最新值 int prev = balance.get(); // 要修改的余额 int next = pre原创 2021-09-07 21:26:32 · 318 阅读 · 0 评论 -
JUC并发编程 共享模式之无锁 -- 保护共享资源(加锁实现 & 无锁实现)
1. 保护共享资源1.1 不安全的实现:账户接口:interface Account { // 获取余额 Integer getBalance(); // 取款 void withdraw(Integer amount); /** * 方法内会启动 1000 个线程,每个线程做 -10 元 的操作 * 如果初始余额为 10000 那么正确的结果应当是 0 */ static void demo(Account ac原创 2021-09-07 20:47:52 · 272 阅读 · 0 评论 -
JUC并发编程 共享模式之内存 有序性 -- happens-before规则(规定了对共享变量的写操作对其它线程的读操作可见)
1. happens-before规则happens-before 规定了对共享变量的写操作对其它线程的读操作可见,它是可见性与有序性的一套规则总结,抛开以下 happens-before 规则,JMM 并不能保证一个线程对共享变量的写,对于其它线程对该共享变量的读可见1.1 规则1线程解锁 m 之前对变量的写,对于接下来对 m 加锁的其它线程对该变量的读可见1.2 规则2线程对 volatile 变量的写,对接下来其它线程对该变量的读可见1.3 规则3线程 start 前原创 2021-09-07 19:53:12 · 185 阅读 · 0 评论 -
JUC并发编程 共享模式之内存 原理之 volatile -- double-checked locking(简介 & 问题分析 & 问题解决)
1. 简介以上的实现特点是:懒惰实例化(只实例化一次)首次使用 getInstance() 才使用 synchronized 加锁,后续使用时无需加锁有隐含的,但很关键的一点:第一个 if 使用了 INSTANCE 变量,是在同步块之外2. 问题分析但在多线程环境下,上面的代码是有问题的,getInstance 方法对应的字节码为:0: getstatic #2 // Field INSTANCE:Lcn/itcast/n5/Singleton;3: ifnonnull 37原创 2021-09-07 19:37:54 · 227 阅读 · 0 评论 -
JUC并发编程 共享模式之内存 原理之 volatile -- 保证可见性 & 保证有序性 & 习题 balking模式
1. 保证可见性写屏障(sfence)保证在该屏障之前的,对共享变量的改动,都同步到主存当中public void actor2(I_Result r) { num = 2; ready = true; // ready 是 volatile 赋值带写屏障 // 写屏障}读屏障(lfence)保证在该屏障之后,对共享变量的读取,加载的是主存中最新数据public void actor1(I_Result r) { // 读屏障 // ready 是 volatile 读取值带原创 2021-09-06 15:27:39 · 242 阅读 · 0 评论 -
JUC并发编程 共享模式之内存 有序性 -- 有序性(指令重排序优化 & 支持流水线的处理器 & 指令重排序的问题/验证/禁用)
1. 指令重排及原理1.1 指令重排1.2 原理原创 2021-09-06 10:16:16 · 330 阅读 · 0 评论 -
JUC并发编程 共享模式之内存 可见性 多线程设计模式 -- 同步模式之 Balking
1. 同步模式之 Balking1.1 定义Balking (犹豫)模式用在一个线程发现另一个线程或本线程已经做了某一件相同的事,那么本线程就无需再做了,直接结束返回1.2 实现例如: public class MonitorService { // 用来表示是否已经有线程已经在执行启动了 private volatile boolean starting; public void start() {原创 2021-09-05 23:54:30 · 158 阅读 · 0 评论 -
JUC并发编程 共享模型之内存 可见性 -- Java 内存模型 & 原子性 & 可见性(可见性问题及解决 & 可见性 VS 原子性 & volatile(易变关键字))
1. Java 内存模型JMM 即 Java Memory Model,它定义了主存(所有线程都共享的数据,包括成员变量)、工作内存(线程私有的数据,包括局部变量)抽象概念,底层对应着 CPU 寄存器、缓存、硬件内存、CPU 指令优化等。JMM 体现在以下几个方面:原子性 - 保证指令不会受到线程上下文切换的影响可见性 - 保证指令不会受 cpu 缓存的影响有序性 - 保证指令不会受 cpu 指令并行优化的影响2. 原子性Monitor 主要关注的是访问共享变量时,保证临界区代码的原原创 2021-09-05 23:33:39 · 220 阅读 · 1 评论 -
JUC并发编程 共享模型之管程 ReentrantLock 多线程设计模式 -- 同步模式之顺序控制( 固定运行顺序 & 交替输出)
1. 固定运行顺序比如,必须先 2 后 1 打印1.1 示例代码01:代码:package tian;import lombok.extern.slf4j.Slf4j;@Slf4j(topic = "c.Test25")public class Test25 { static final Object lock = new Object(); // 表示 t2 是否运行过 static boolean t2runned = false; public原创 2021-09-05 21:34:16 · 251 阅读 · 0 评论 -
JUC并发编程 共享模型之管程 ReentrantLock -- ReentrantLock可重入锁( 公平锁 & 条件变量 )
1. 公平锁所谓公平锁,就是线程在EnteyList排队时必须先来后到,不可以插队。ReentrantLock 默认是不公平的公平锁一般没有必要,会降低并发度2. 条件变量2.1 概念:synchronized 中也有条件变量,就是我们讲原理时那个 waitSet 休息室,当条件不满足时进入 waitSet 等待ReentrantLock 的条件变量比 synchronized 强大之处在于,它是支持多个条件变量的,这就好比:synchronized 是那些不满足条件的线程都在一间原创 2021-09-05 20:28:09 · 214 阅读 · 1 评论