
JUC
文章平均质量分 52
Q z1997
这个作者很懒,什么都没留下…
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
Semaphore 原理
接下来 Thread-0 竞争成功,permits 再次设置为 0,设置自己为 head 节点,断开原来的 head 节点,unpark 接下来的 Thread-3 节点,但由于 permits 是 0,因此 Thread-3 在尝试不成功后再次进入 park 状态。假设其中 Thread-1,Thread-2,Thread-4 cas 竞争成功,而 Thread-0 和 Thread-3 竞争失败,进入 AQS 队列park 阻塞。刚开始,permits(state)为 3,这时 5 个线程来获取资源。原创 2022-08-24 22:22:18 · 306 阅读 · 0 评论 -
特殊的读写锁 StampedLock
乐观读,StampedLock 支持 tryOptimisticRead() 方法(乐观读),读取完毕后需要做一次 戳校验 如果校验通过,表示这期间确实没有写操作,数据可以安全使用,如果校验没通过,需要重新获取读锁,保证数据安全。该类自 JDK 8 加入,是为了进一步优化读性能,它的特点是在使用读锁、写锁时都必须配合【戳】使用加解读锁。提供一个 数据容器类 内部分别使用读锁保护数据的 read() 方法,写锁保护数据的 write() 方法。原创 2022-08-24 22:17:01 · 258 阅读 · 0 评论 -
读写锁原理
读写锁原理原创 2022-08-21 15:57:23 · 152 阅读 · 0 评论 -
读写锁的应用
读写锁单机更新缓存原创 2022-08-21 15:39:55 · 233 阅读 · 0 评论 -
ReentrantReadWriteLock读写锁
提供一个 数据容器类 内部分别使用读锁保护数据的 read() 方法,写锁保护数据的 write() 方法。当读操作远远高于写操作时,这时候使用 读写锁 让 读-读 可以并发,提高性能。重入时降级支持:即持有写锁的情况下去获取读锁。写锁-写锁 也是相互阻塞的,这里就不测试了。测试 读锁-读锁 可以并发。测试 读锁-写锁 相互阻塞。原创 2022-08-21 15:23:43 · 460 阅读 · 0 评论 -
ReentrantLock 原理
ReentrantLock 原理原创 2022-08-01 20:17:18 · 123 阅读 · 0 评论 -
AQS原理和介绍
队列中有head和tail两个指针节点,都用volatile修饰配合cas使用,每个节点有state维护节点状态。早期程序员会自己通过一种同步器去实现另一种相近的同步器,例如用可重入锁去实现信号量,或反之。够优雅,于是在JSR166(java规范提案)中创建了AQS,提供了这种通用的同步器机制。入队伪代码,只需要考虑tail赋值的原子性。主要用到AQS的并发工具类。AQS的基本思想其实很简单。AQS要实现的功能目标。自定义锁的实现和测试。...原创 2022-07-31 19:22:56 · 173 阅读 · 0 评论 -
Fork/Join线程池
Fork/Join线程池。原创 2022-07-31 19:14:54 · 433 阅读 · 0 评论 -
任务调度线程池-应用定时任务
任务调度线程池-应用定时任务。原创 2022-07-31 19:07:22 · 250 阅读 · 0 评论 -
线程池处理异常的方法
线程池处理异常的方法原创 2022-07-31 19:03:52 · 620 阅读 · 0 评论 -
任务调度线程池基本介绍
在『任务调度线程池』功能加入之前,可以使用java.util.Timer来实现定时功能,Timer的优点在于简单易用,但由于所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任务。输出分析一开始,延时1s,scheduleWithFixedDelay的间隔是上一个任务结束延时下一个任务开始所以间隔都是3s。评价整个线程池表现为线程数固定,任务数多于线程数时,会放入无界队列排队。...原创 2022-07-31 19:02:37 · 313 阅读 · 0 评论 -
Java 线程池的基本介绍
ThreadPoolExecutor使用int的高3位来表示线程池状态,低29位表示线程数量状态名高3位接收新任务处理阻塞队列任务说明RUNNING111YY-SHUTDOWN000NY不会接收新任务,但会处理阻塞队列剩余任务STOP001NN会中断正在执行的任务,并抛弃阻塞队列任务TIDYING010--任务全执行完毕,活动线程为0即将进入终结TERMINATED011--终结状态。...原创 2022-07-29 19:59:48 · 142 阅读 · 0 评论 -
手写Java的线程池
简单实现了一个Java的线程池阻塞队列线程池测试代码测试结果原创 2022-07-26 20:12:18 · 343 阅读 · 0 评论 -
简单实现数据库链接池
简单实现的数据库连接池原创 2022-06-04 22:37:32 · 113 阅读 · 0 评论 -
final 原理
理解了 volatile 原理,再对比 final 的实现就比较简单了字节码发现 final 变量的赋值也会通过 putfield 指令来完成,同样在这条指令之后也会加入写屏障,保证在其它线程读到它的值时不会出现为 0 的情况不用使用final (低于short)使用final(低于short)加 final 使用常量池(高于short)不加 final 使用常量池(高于short)...原创 2022-06-04 22:34:58 · 188 阅读 · 0 评论 -
共享模型之不可变
问题提出下面的代码在运行时,由于 SimpleDateFormat 不是线程安全的有很大几率出现 java.lang.NumberFormatException 或者出现不正确的日期解析结果,例如:思路 - 同步锁这样虽能解决问题,但带来的是性能上的损失,并不算很好:思路 - 不可变如果一个对象在不能够修改其内部状态(属性),那么它就是线程安全的,因为不存在并发修改啊!这样的对象在Java 中有很多,例如在 Java 8 后,提供了一个新的日期格式化类:可以看 DateTimeFormatt原创 2022-06-04 22:24:21 · 92 阅读 · 0 评论 -
JUC Unsafe
概述Unsafe 对象提供了非常底层的,操作内存、线程的方法,Unsafe 对象不能直接调用,只能通过反射获得Unsafe CAS 操作原创 2022-06-02 17:27:32 · 101 阅读 · 0 评论 -
JUC 原子累加器 源码之 LongAdder
LongAdder 是并发大师 @author Doug Lea (大哥李)的作品,设计的非常精巧LongAdder 类有几个关键域cas 锁其中 Cell 即为累加单元得从缓存说起缓存与内存的速度比较因为 Cell 是数组形式,在内存中是连续存储的,一个 Cell 为 24 字节(16 字节的对象头和 8 字节的 value),因此缓存行可以存下 2 个的 Cell 对象。这样问题来了:@sun.misc.Contended 用来解决这个问题,它的原理是在使用此注解的对象或字段的前后各增原创 2022-06-02 17:25:37 · 157 阅读 · 0 评论 -
JUC 原子累加器
比较 AtomicLong 与 LongAdder输出性能提升的原因很简单,就是在有竞争时,设置多个累加单元,Therad-0 累加 Cell[0],而 Thread-1 累加Cell[1]… 最后将结果汇总。这样它们在累加时操作的不同的 Cell 变量,因此减少了 CAS 重试失败,从而提高性能。原创 2022-06-02 17:20:46 · 143 阅读 · 0 评论 -
JUC 字段更新器
AtomicReferenceFieldUpdater // 域 字段利用字段更新器,可以针对对象的某个域(Field)进行原子操作,只能配合 volatile 修饰的字段使用,否则会出现异常原创 2022-06-02 17:19:10 · 122 阅读 · 0 评论 -
JUC原子数组
AtomicIntegerArray原创 2022-06-02 17:17:47 · 142 阅读 · 0 评论 -
JUC原子引用与ABA问题
JUC原子引用ABA 问题及解决ABA 问题主线程仅能判断出共享变量的值与最初值 A 是否相同,不能感知到这种从 A 改为 B 又 改回 A 的情况,如果主线程希望:只要有其它线程【动过了】共享变量,那么自己的 cas 就算失败,这时,仅比较值是不够的,需要再加一个版本号AtomicStampedReference 可以给原子引用加上版本号,追踪原子引用整个的变化过程,如: A -> B -> A -> C ,通过AtomicStampedReference,我们可以知道,引用变量中途被更改了几次原创 2022-06-02 17:16:05 · 113 阅读 · 0 评论 -
JUC原子整数
J.U.C 原子整数原创 2022-06-02 10:41:03 · 100 阅读 · 0 评论 -
CAS无锁
有如下需求,保证 取款方法的线程安全原有实现并不是线程安全的某次的执行结果解决思路-锁首先想到的是给 Account 对象加锁结果为解决思路-无锁执行测试代码某次的执行结果CAS 与 volatile前面看到的 AtomicInteger 的解决方法,内部并没有用锁来保护共享变量的线程安全。那么它是如何实现的呢?其中的关键是 compareAndSet,它的简称就是 CAS (也有 Compare And Swap 的说法),它必须是原子操作。注意其实 CAS 的底层是 loc原创 2022-06-02 10:38:03 · 128 阅读 · 0 评论 -
double-checked locking双重验锁 多线程顺序新问题
public final class Singleton { private Singleton() { } private static Singleton INSTANCE = null; public static Singleton getInstance() { if(INSTANCE == null) { // t2 // 首次访问会同步,而之后的使用没有 synchronized synchronized(Singleton.class) { if (INSTANCE == n原创 2022-05-27 14:28:20 · 89 阅读 · 0 评论 -
volatile 原理
volatile 原理volatile 的底层实现原理是内存屏障,Memory Barrier(Memory Fence)对 volatile 变量的写指令后会加入写屏障对 volatile 变量的读指令前会加入读屏障如何保证可见性写屏障(sfence)保证在该屏障之前的,对共享变量的改动,都同步到主存当中public void actor2(I_Result r) { num = 2; ready = true; // ready 是 volatile 赋值带写屏障 // 写屏障}原创 2022-05-27 14:11:51 · 154 阅读 · 0 评论 -
happens-before可见性
happens-before可见性happens-before 规定了对共享变量的写操作对其它线程的读操作可见,它是可见性与有序性的一套规则总结,抛开以下 happens-before 规则,JMM 并不能保证一个线程对共享变量的写,对于其它线程对该共享变量的读可见线程解锁 m 之前对变量的写,对于接下来对 m 加锁的其它线程对该变量的读可见static int x;static Object m = new Object();new Thread(()->{ synchronized原创 2022-05-27 11:45:47 · 146 阅读 · 0 评论 -
Java 内存模型 (JMM)
Java 内存模型JMM 即 Java Memory Model,它定义了主存、工作内存抽象概念,底层对应着 CPU 寄存器、缓存、硬件内存、CPU 指令优化等。JMM 体现在以下几个方面原子性 - 保证指令不会受到线程上下文切换的影响可见性 - 保证指令不会受 cpu 缓存的影响有序性 - 保证指令不会受 cpu 指令并行优化的影响原子性保证指令不会受到线程上下文切换的影响(参考之前的文章)可见性先来看一个现象,main 线程对 run 变量的修改对于 t 线程不可见,导致了 t 线原创 2022-05-26 17:12:28 · 148 阅读 · 0 评论 -
Java多线程交替打印
Wait/Notifypackage com.example.demo.hmjuc.day15;import lombok.AllArgsConstructor;/** * @author zhangqi * @date 2022/5/25 20:39 */public class Test2 { public static void main(String[] args) { Wn wn = new Wn(1, 3); new Thread(()原创 2022-05-26 14:32:39 · 929 阅读 · 0 评论 -
多线程交替输出
wait notifypackage com.example.demo.hmjuc.day14;import lombok.extern.slf4j.Slf4j;/** * @author zhangqi * @date 2022/5/15 18:34 */@Slf4jpublic class Test1 { private static final Object LOCK = new Object(); private static boolean flag = fal原创 2022-05-15 19:10:50 · 101 阅读 · 0 评论 -
Java线程池
为啥要有线程池为了避免系统频繁地创建和销毁线程,我们可以让创建的线程复用。如果大家进行过数据库开发,那么对数据库连接池应该不会陌生。为了避免每次数据库查询都重新建立和销毁数据库连接,我们可以使用数据库连接池维护一些数据库连接,让它们长期保持在一个激活状态。当系统需要使用数据库时,并不是创建一个新的连接,而是从连接池中获得一个可用的连接即可。反之,当需要关闭连接时,并不真的把连接关闭,而是将这个连接“还”给连接池即可。这种方式可以节约不少创建和销毁对象的时间。线程池也是类似的概念。在线程池中,总有那么几个原创 2022-05-13 17:22:29 · 170 阅读 · 0 评论 -
CyclicBarrier: 循环栅栏
CyclicBarrier是另外一种多线程并发控制工具。和CountDownLatch非常类似,它也可以实现线程间的计数等待,但它的功能比CountDownLatch更加复杂且强大。CyclicBarrier可以理解为循环栅栏。栅栏就是一种障碍物,比如,通常在私人宅邸的周围就可以围上一圈栅栏,阻止闲杂人等入内。这里当然就是用来阻止线程继续执行,要求线程在栅栏外等待。前面Cyclic意为循环,也就是说这个计数器可以反复使用。比如,我们将计数器设置为10,那么凑齐第一批10个线程后,计数器就会归零,接着凑齐下原创 2022-05-13 10:23:00 · 315 阅读 · 0 评论 -
CountDownLatch倒计数器
CountDownLatch是一个非常实用的多线程控制工具类。“Count Down”在英文中意为倒计数,Latch意为门闩的意思。如果翻译成为倒计数门闩,我想大家都会不知所云吧!因此,这里简单地称之为倒计数器。在这里,门门的含义是把门锁起来,不让里面的线程跑出来。因此,这个工具通常用来控制线程等待,它可以让某一个线程等待直到倒计数结束,再开始执行。对于倒计数器,一种典型的场景就是火箭发射。在火箭发射前,为了保证万无一失,往往还要对各项设备、仪器进行检查。只有等所有检查都完成后,引擎才能点火。这种场景就非常原创 2022-05-12 15:52:57 · 233 阅读 · 0 评论 -
读写锁ReadWriteLock
ReadWriteLock是JDK5.0新增的一个类,它可以实现读写分离锁. 读写分离锁可以有效的减少锁的竞争,提升系统性能。用锁分离的机制来提升性能非常容易理解,比如线程A1、A2、A3进行写操作,B1、B2、B3进行读操作,如果使用重入锁或者内部锁,从理论上说所有读之间、读与写之间、写和写之间都是串行操作。当B1进行读取时,B2、B3则需要等待锁。由于读操作并不对数据的完整性造成破坏,这种等待显然是不合理的。因此,读写锁就有了发挥功能的余地。在这种情况下,读写锁允许多个线程同时读,使得B1、B2、B3原创 2022-05-12 15:29:33 · 345 阅读 · 0 评论 -
信号量Semaphore
信号量Semaphore信号量为多线程协作提供了更为强大的控制方法。从广义上说,信号量是对锁的扩展。无论是内部锁synchronized还是重入锁ReentrantLock,一次都只允许一个线程访问一个资源,而信号量却可以指定多个线程,同时访问某一个资源。信号量主要提供了以下构造函数:创建一个信号量,初始值为5 代表可以同时访问5个资源如果超过5个线程访问,则会一直等待 第二个参数可以指定是否公平 final Semaphore semp = new Semaphore(5); fin原创 2022-05-12 14:53:35 · 223 阅读 · 0 评论 -
ReentrantLock解决死锁
package com.example.demo.hmjuc.day12;import java.util.concurrent.locks.ReentrantLock;/** * @author zhangqi * @date 2022/5/12 12:14 */public class IntLock implements Runnable { public static ReentrantLock lockl = new ReentrantLock(); public原创 2022-05-12 12:23:15 · 796 阅读 · 0 评论 -
并行的两个重要定律
并行的两个重要定律Amdahl 定律Amdahl 定律是计算机科学中非常重要的定律。它定义了串行系统并行化后的加速 比的计算公式和理论上限加速比定义:加速比=优化前系统耗时 优化后系统耗时所谓加速比就是优化前 耗时与优 后耗时 的比值。 加速比越 明优化效果越明显。 显示了 mdahl 公式的推导 ,其中 表示处理器个数, 表示时间, T1 表示优化前耗时(也就是只有 处理器时的耗时) , 表示使用 个处理器优化后的耗时。是程序 只能串行执行的 比例根据这个公式,如果 CPU 处理器数原创 2022-05-12 10:47:53 · 1375 阅读 · 0 评论 -
ReentrantLock简介和使用
ReentrantLock简介和使用相对于 synchronized 它具备如下特点可中断可以设置超时时间可以设置为公平锁支持多个条件变量与 synchronized 一样,都支持可重入基本语法:// 获取锁reentrantLock.lock();try { // 临界区} finally { // 释放锁 reentrantLock.unlock();}可重入可重入是指同一个线程如果首次获得了这把锁,那么因为它是这把锁的拥有者,因此有权利再次获取这把锁如果是不可重原创 2022-05-12 10:02:24 · 334 阅读 · 0 评论 -
线程活跃性
死锁有这样的情况:一个线程需要同时获取多把锁,这时就容易发生死锁t1 线程 获得 A对象 锁,接下来想获取 B对象 的锁 t2 线程 获得 B对象 锁,接下来想获取 A对象 的锁 例:package com.example.demo.hmjuc.day10;import com.example.demo.hmjuc.Sleep;/** * 死锁演示 * * @author zhangqi * @date 2022/5/5 20:15 */public class Test1 {原创 2022-05-09 15:11:23 · 331 阅读 · 0 评论 -
深入理解线程的状态
假设有线程 Thread t情况 1 NEW --> RUNNABLE当调用 t.start() 方法时,由 NEW --> RUNNABLE情况 2 RUNNABLE <–> WAITINGt 线程用 synchronized(obj) 获取了对象锁后调用 obj.wait() 方法时,t 线程从 RUNNABLE --> WAITING调用 obj.notify() , obj.notifyAll() , t.interrupt() 时竞争锁成功,t 线.原创 2022-05-05 09:41:26 · 64 阅读 · 0 评论