
JAVA并发编程
文章平均质量分 81
失业找工作中
it小白的学习笔记,加油!
展开
-
JAVA并发编程
JUC就是java.util.concurrent工具包的简称。这是一个处理线程的工具包, JDK1.5开始出现的。• 1、进程与线程• 2、Lock接口• 3、线程间通信• 4、集合的线程安全• 5、多线程锁• 6、Callable接口• 7、JUC三大辅助类: CountDownLatch CyclicBarrier Semaphore• 8、读写锁: ReentrantReadWriteLock• 9、阻塞队列• 10、ThreadPool线程池• 11、Fork/Join框架原创 2017-12-09 20:47:56 · 317 阅读 · 0 评论 -
volatile的变量可见性问题探讨
文章目录变量的可见性不加volatile原因:JIT在搞鬼证明JIT优化的对象和触发条件(1)基于采样的热点探测(2)基于计数器的热点探测加volatile其他情况volatile变量的读写保证可见性总结对于未被volatile修饰的变量的可见性可以用一句玄乎的话表达:不加volatile是不一定保证但不代表一定不可见申明本文演示的现象仅仅是当前这些代码的语境和HotSpot现有的JIT编译器实现产生的,不能确保在其他JVM与所有CPU架构上都一定相同(肯定是不一样的)。变量的可见性不加volati原创 2021-09-30 22:55:15 · 445 阅读 · 0 评论 -
CyclicBarrier源码解析
文章目录关键属性内部类Generation构造函数wait()阻塞等待定时等待dowait()nextGeneration()breakBarrier()重置已到达等待线程数CyclicBarrier栅栏,与CountDownLatch类似,但不是基于AQS实现的同步器,用于多个线程之间等待。CyclicBarrier每次使用完之后可以重置,CountDownLatch不可重置,CyclicBarrier同步一组线程,在CyclicBarrier类的内部有一个计数器,每个线程在到达屏障点的时候都会调用原创 2021-09-28 19:06:40 · 206 阅读 · 0 评论 -
源码解析AQS的PROPAGATE有什么用?
文章目录AQS的PROPAGATE有什么用?bug修复前的代码正常流程产生 bug 的情况bug 修复后的代码AQS的PROPAGATE有什么用?waitStatus=PROPAGATE值为-3,当前线程处在SHARED共享模式下,该字段才会使用比如信号量Semaphore,读写锁ReentrantReadWriteLock的读锁等这里用信号量Semaphore为例bug修复前的代码假设存在某次循环中队列里排队的结点情况为 head(-1)->t1(-1)->t2(-1)假设存在原创 2021-09-28 09:28:45 · 621 阅读 · 0 评论 -
Semaphore 源码解析
文章目录semaphore 实现semaphore 原理加锁解锁流程获得许可tryAcquireShared(arg)doAcquireSharedInterruptibly(arg)addWaiter(Node.SHARED)enq(node)shouldParkAfterFailedAcquire(p, node)parkAndCheckInterrupt()释放许可tryReleaseShared(arg)doReleaseShared()unparkSuccessor(h)唤醒Thread-0set原创 2021-09-28 08:20:23 · 271 阅读 · 0 评论 -
StampedLock源码解析
文章目录属性构造函数内部类写锁的获取、释放1.写锁的获取2.写锁的释放读锁的获取和释放1.读锁的获取2.读锁的释放乐观读锁获取、校验1.乐观读锁的获取2.乐观读锁的校验锁转换1.转换为写锁2.转换为读锁3.转换乐观读StampedLock没有直接实现ReadWriteLock,但是提供了方法可以返回ReadWriteLock接口的实现类,如下:public Lock asReadLock() { ReadLockView v; return ((v = readLockView) !=原创 2021-09-27 20:57:15 · 125 阅读 · 0 评论 -
StampedLock邮戳锁
文章目录StampedLock是什么由锁饥饿问题引出StampedLock如何缓解锁饥饿问题?1 使用“公平”策略可以一定程度上缓解这个问题2 StampedLock类的乐观读锁闪亮登场 是对读写锁的补充StampedLock的特点乐观读模式code演示StampedLock的缺点StampedLock是什么StampedLock是JDK1.8中新增的一个读写锁,也是对JDK1.5中的读写锁ReentrantReadWriteLock的读性能的优化。邮戳锁也叫票据锁有一个stamp变量(戳记,l原创 2021-09-27 20:54:57 · 489 阅读 · 0 评论 -
ReentrantReadWriteLock源码解析
文章目录源码分析t1 w.lock,t2 r.lockt1执行 w.lock成功上锁,tryAcquire(arg)writerShouldBlock()t2 执行 r.lock,tryAcquireShared(arg)doAcquireShared(arg)addWaiter()tryAcquireShared()t3 r.lock,t4 w.lockt3 r.lockt4 w.locktryAcquire(arg)addWaiter(Node.EXCLUSIVE), arg)t1 w.unlocktr原创 2021-09-27 18:28:57 · 113 阅读 · 0 评论 -
ReentrantReadWriteLock读写锁
文章目录ReentrantReadWriteLockReentrantReadWriteLock 类的整体结构写锁的获取和释放读锁的获取与释放读写锁的意义读写锁有以下三个重要的特性:注意事项读写锁的演变读写锁演变案例无锁实现使用ReentrantLock使用ReentrantReadWriteLock读写锁的降级jdk8写锁降级为读锁过程锁降级使用场景先写后读案例那么先读再写会怎么样呢?不可锁升级ReentrantWriteLock应用实践之缓存使用hashmap实现缓存缓存更新策略读写锁实现一致性缓存总结原创 2021-09-27 12:26:41 · 389 阅读 · 1 评论 -
ReentrantLock源码解析(二)
文章目录可重入原理加锁解锁可打断原理不可打断模式可打断模式条件变量实现原理await流程addConditionWaiter()fullyRelease ()park()signal 流程isHeldExclusively()doSignal ()transferForSignal ()unlock 流程可重入原理仍然以非公平锁为例加锁/** * Performs non-fair tryLock. tryAcquire is implemented in * subclasses, but原创 2021-09-26 21:29:43 · 107 阅读 · 0 评论 -
从ReentrantLock源码解读AQS
文章目录ReentrantLock的原理公平锁实现原理(了解)加锁源码解锁源码非公平锁实现原理加锁源码解锁源码用模拟银行办理业务来源码解读非公平锁当A执行lock()B执行lock()tryAcquire(arg)addWaiter(Node.EXCLUSIVE)acquireQueued(addWaiter(node, arg)tryAcquire(arg)shouldParkAfterFailedAcquire(p, node)C执行lock()tryAcquire(arg)addWaiter(Node原创 2021-09-26 15:56:43 · 128 阅读 · 0 评论 -
AbstractQueuedSynchronizer
早期程序员会自己通过一种同步器去实现另一种相近的同步器,例如用可重入锁去实现信号量,或反之。这显然不够优雅,于是在JDK1.5中新增了 AQS,提供了这种通用的同步器机制。是什么抽象的队列同步器AbstractOwnableSynchronizerAbstractQueuedLongSynchronizerAbstractQueuedSynchronizer通常地:AbstractQueuedSynchronizer简称为AQS是用来构建锁或者其它同步器组件的重量级基础框架及整个JUC体原创 2021-09-26 15:47:21 · 286 阅读 · 0 评论 -
Java对象内存布局
对象在堆内存中布局摘自周志明老师JVM第3版对象内部结构分为:对象头、实例数据、对齐填充(保证8个字节的倍数)。对象头分为对象标记(markword,类元信息/类型指针(Class Pointer ) -java层面的对象标记(markOop)和类元信息(klassOop),类元信息存储的是指向该对象类元数据(klass)的首地址。 --c++层面的对齐填充就是保证8个字节的倍数对象头对象头分为Mark Word 对象标记和Class Pointer 类型指针Java对象头里的M原创 2021-09-26 08:54:04 · 231 阅读 · 0 评论 -
ThreadLocal
ThreadLocal概述是什么官网:稍微翻译一下:ThreadLocal提供线程局部变量。这些变量与正常的变量不同,因为每一个线程在访问ThreadLocal实例的时候(通过其get或set方法)都有自己的、独立初始化的变量副本。ThreadLocal实例通常是类中的私有静态(private static)字段,使用它的目的是希望将状态(例如,用户ID或事务ID)与线程关联起来。能干嘛实现每一个线程都有自己专属的本地变量副本(自己用自己的变量不麻烦别人,不和其他人共享,人人有份,人各一份),原创 2021-09-25 14:14:05 · 332 阅读 · 0 评论 -
JVM四大引用(强引用、软引用、弱引用、虚引用)
强引用、软引用、弱引用、虚引用分别是什么?Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。新建一个带finalize()方法的对象MyObjectclass MyObject{ //一般开发中不用调用这个方法,本次只是为了讲课演示 @Override protected void finalize() throws Throwable{ System.out.println(Thread.curre原创 2021-09-25 14:13:29 · 180 阅读 · 0 评论 -
LongAdder源码解析
LongAdder源码上一篇文章对比了LongAdder、LongAccumulator 性能要比AtomicLong快那么我们看一看LongAdder为什么这么快吧。架构LongAdder是Striped64的子类public class LongAdder extends Striped64 implements Serializable { private static final long serialVersionUID = 7249069246863182397L;原创 2021-09-25 09:00:44 · 153 阅读 · 0 评论 -
Java使用Unsafe类
Unsafe 对象提供了非常底层的,操作内存、线程的方法,相当于开了后门。在atomic类中CAS实现、LockSupport中park unpark的底层都调用了UnSafe中的方法。UnSafe并不是说线程不安全,而是说操作内存有可能会造成不安全问题。当然对于开发人员来说Unsafe 对象不能直接调用,只能通过反射获得通过反射获得Unsafe对象package com.dongguo.unsafe;import sun.misc.Unsafe;import java.lang.re原创 2021-09-24 20:09:05 · 269 阅读 · 0 评论 -
atomic
原子操作原子(atomic)本意是“不能被进一步分割的最小粒子”,而原子操作(atomic operation)意为“不可被中断的一个或一系列操作”。处理器如何实现原子操作最新的处理器能自动保证单处理器对同一个缓存行里进行16/32/64位的操作是原子的,但是复杂的内存操作处理器是不能自动保证其原子性的,比如跨总线宽度、跨多个缓存行和跨页表的访问。但是,处理器提供总线锁定和缓存锁定两个机制来保证复杂内存操作的原子性。使用总线锁保证原子性如果多个处理器同时对共享变量进行读改写操作(i++就是经典原创 2021-09-24 19:25:22 · 328 阅读 · 0 评论 -
CAS源码解析
在没有CAS之前多线程环境可以使用 读用volatile 、写用锁保证线程安全(基本数据类型)public class T3{ volatile int number = 0; //读取 public int getNumber() { return number; } //写入加锁保证原子性 public synchronized void setNumber() { number++; }}原创 2021-09-24 16:30:37 · 1467 阅读 · 0 评论 -
volatile与Java内存模型
在多线程并发编程中synchronized和volatile都扮演着重要的角色,Volatile是轻量级的同步机制 是一个可以保证线程安全的关键字。它在并发编程中保证了共享变量的“可见性”。可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。如果volatile变量修饰符使用恰当的话,它比synchronized的使用和执行成本更低,因为它不会引起线程上下文的切换和调度。volatile的内存语义即 Volatile如何保证内存可见性:当写一个volatile变量时,JMM原创 2021-09-23 08:51:36 · 364 阅读 · 0 评论 -
Java内存模型之JMM
Java内存模型Java Memory ModelJMM(Java内存模型Java Memory Model,简称JMM)本身是一种抽象的概念并不真实存在它仅仅描述的是一组约定或规范,通过这组规范定义了程序中(尤其是多线程)各个变量的读写访问方式并决定一个线程对共享变量的写入何时以及如何变成对另一个线程可见,Java线程之间的通信由Java内存模型(本文简称为JMM)控制,JMM决定一个线程对共享变量的写入何时对另一个线程可见。从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量原创 2021-09-23 08:48:59 · 250 阅读 · 1 评论 -
LockSupport(park&unpark)源码解析
LockSupport(park/unpark)源码解析park方法park()public static void park() { UNSAFE.park(false, 0L);}park(Object blocker)public static void park(Object blocker) { Thread t = Thread.currentThread(); setBlocker(t, blocker); UNSAFE.park(false, 0原创 2021-09-21 08:01:02 · 953 阅读 · 0 评论 -
LockSupport与线程等待唤醒机制
LockSupport是什么LockSupport线程工具类 定义了许多方法来控制当前线程 俗称 锁中断是用来创建锁和其他同步类的基本线程阻塞原语。LockSupport中的park()和unpark()分别是阻塞线程和解除阻塞线程LockSupport类使用了一种名为Permit(许可)的概念来做到阻塞和唤醒线程的功能, 每个线程都有一个许可, 许可只有两个值1和零,默认是零。 可以把许可看成是一种(0,1)信号量(Semaphore),但与 Semaphore 不同的是,许可的累加上限是1。原创 2021-09-21 07:59:51 · 294 阅读 · 0 评论 -
线程中断机制interrupt
## 什么是中断首先一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止。所以,Thread.stop, Thread.suspend, Thread.resume 都已经被废弃了。其次在Java中没有办法立即停止一条线程,然而停止线程却显得尤为重要,如取消一个耗时操作。因此,Java提供了一种用于停止线程的机制——中断。原创 2021-09-20 09:56:17 · 733 阅读 · 0 评论 -
CompletableFuture异步回调
FutureFuture接口定义了操作异步任务执行一些方法,如获取异步任务的执行结果、取消任务的执行、判断任务是否被取消、判断任务执行是否完毕等。比如我们将任务提交到线程池里面,然后我们会得到一个Futrue,在Future里面有isDone方法来 判断任务是否处理结束,还有get方法可以一直阻塞直到任务结束然后获取结果,(最好放在最后)但整体来说这种方式,还是同步的,因为需要客户端不断阻塞等待或者不断轮询才能知道任务是否完成。Future的主要缺点如下:(1)不支持手动完成我提交了一个任务,但是执原创 2021-09-19 20:30:03 · 991 阅读 · 1 评论 -
ForkJoin框架
介绍Fork/Join 是 JDK 1.7 加入的新的线程池实现,它体现的是一种分治思想,适用于能够进行任务拆分的 cpu 密集型运算Fork/Join它可以将一个大的任务拆分成多个子任务进行并行处理,最后将子任务结果合并成最后的计算结果,并进行输出。Fork/Join框架要完成两件事情:Fork:把一个复杂任务进行分拆,大事化小Join:把分拆任务的结果进行合并Fork/Join 在分治的基础上加入了多线程,可以把每个任务的分解和合并交给不同的线程来完成,进一步提升了运算效率Fork/Jo原创 2021-09-19 15:01:33 · 177 阅读 · 0 评论 -
ThreadPool线程池
介绍线程池(英语:thread pool):一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。线程池的优势:线程池做的工作只要是控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。它的主要特点为:原创 2021-09-19 15:01:05 · 338 阅读 · 0 评论 -
JUC工具类Phaser
简介java7中引入了一种新的可重复使用的同步屏障,Phaser阶段器,与CyclicBarrier和CountDownLatch类似,但更强大。CyclicBarrier解决了CountDownLatch不能重用的问题,但是仍有以下不足:1)不能动态调整计数器值,假如线程数不足以打破barrier,就只能reset或者多加些线程,在实际运用中显然不现实2)每次await仅消耗1个计数器值,不够灵活Phaser就是用来解决这些问题的。Phaser将多个线程协作执行的任务划分为多个阶段,每个阶段都可原创 2021-09-19 13:59:45 · 255 阅读 · 0 评论 -
JUC工具类Exchanger
Exchanger概念线程可以在成对内配对和交换元素的同步点。每个线程在输入exchange方法时提供一些对象,与合作者线程匹配,并在返回时接收其合作伙伴的对象。交换器可以被视为一个的双向形式SynchronousQueue。交换器在诸如遗传算法和管道设计的应用中可能是有用的。一个用于两个工作线程之间交换数据的封装工具类,简单说就是一个线程在完成一定的事务后想与另一个线程交换数据,则第一个先拿出数据的线程会一直等待第二个线程,直到第二个线程拿着数据到来时才能彼此交换对应数据。用法Exchange原创 2021-09-19 13:59:09 · 175 阅读 · 0 评论 -
JUC强大的辅助工具类
JUC中提供了一些辅助类,通过这些辅助类可以很好的解决线程数量过多时Lock锁的频繁操作。常用的三种辅助类有:• CountDownLatch: 减少计数• CyclicBarrier: 循环栅栏• Semaphore: 信号灯CountDownLatchCountDownLatch是一个同步工具类,用来进行线程同步协作,等待所有线程完成倒计时。CountDownLatch类可以设置一个计数器,然后通过countDown方法来进行减1的操作,使用await方法等待计数器不大于0,然后继续执行aw原创 2021-09-19 13:57:53 · 222 阅读 · 0 评论 -
BlockingQueue阻塞队列
BlockingQueue简介阻塞队列,顾名思义,首先它是一个队列, 通过一个共享的队列,可以使得数据由队列的一端输入,从另外一端输出;当队列是空的,从队列中获取元素的操作将会被阻塞当队列是满的,从队列中添加元素的操作将会被阻塞试图从空的队列中获取元素的线程将会被阻塞,直到其他线程往空的队列插入新的元素试图向已满的队列中添加新元素的线程将会被阻塞,直到其他线程从队列中移除一个或多个元素或者完全清空,使队列变得空闲起来并后续新增阻塞队列是一个队列,在数据结构中起的作用如下图:线程1往阻塞队列里原创 2021-09-19 10:46:38 · 254 阅读 · 0 评论 -
使用Callable接口创建线程
创建线程的方法一种是通过创建Thread类,另一种是通过使用Runnable创建线程。但是,Runnable缺少的一项功能是,当线程终止时(即run()完成时),我们无法使线程返回结果。为了支持此功能,Java中提供了Callable接口。当然了还可以使用线程池创建线程。Callable接口和Runnable接口的区别Callable接口中定义了需要有返回的任务需要实现的call方法。比如主线程让一个子线程去执行任务,子线程可能比较耗时,启动子线程开始执行任务后,主线程就去做其他事情了,过了一会原创 2021-09-18 17:17:42 · 2024 阅读 · 0 评论 -
锁优化(锁升级、锁粗化、锁消除)
锁优化阿里开发手册synchronized 锁优化的背景用锁能够实现数据的安全性,但是会带来性能下降。无锁能够基于线程并行提升程序性能,但是会带来安全性下降。要在性能与安全找到平衡点:jdk6引入偏向锁、轻量级锁Synchronized的性能变化Java5之前,用户态和内核态之间的切换java5以前,只有Synchronized,这个是操作系统级别的重量级操作重量级锁,假如锁的竞争比较激烈的话,性能下降‘java的线程是映射到操作系统原生线程之上的,如果要阻塞或唤醒一个线程就需要操原创 2021-09-17 13:41:40 · 1715 阅读 · 0 评论 -
自旋锁SpinLock
自旋锁SpinLock自旋锁,借鉴CAS思想是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,当线程发现锁被占用时,会不断循环判断锁的状态,直到获取。这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPUOpenJDK源码里面查看下Unsafe.java do while循环自己实现一个自旋锁SpinLockDemopackage com.dongguo.cas;import java.util.concurrent.TimeUnit;import java.u原创 2021-09-16 09:04:16 · 166 阅读 · 0 评论 -
悲观锁乐观锁
悲观锁/乐观锁悲观锁悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别的线程会修改,所以每次在拿数据的时候都会上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。适合写操作多的场景,先加锁可以保证写操作时数据正确。显式的锁定之后再操作同步资源 //=============悲观锁的调用方式public synchronized void m1(){ //加锁后的业务逻辑......}// 保证多个线程使用的是同一个lock对象的原创 2021-09-16 09:03:41 · 134 阅读 · 0 评论 -
锁的活跃性(死锁、活锁、饥饿)
死锁锁是个非常有用的工具,运用场景非常多,它使用起来非常简单,而且易于理解。但同时它也会带来一些困扰,那就是可能会引起死锁,一旦产生死锁,就会造成系统功能不可用。定义线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,会互相等待对方释放资源,如果线程都不主动释放所占有的资源,将产生死锁。死锁的产生的一些特定条件:1、互斥条件:即一个资源只能被一个线程占用,直到被该线程释放 。2、请求和保持条件:一个线程因请求资源而发生阻塞时,对已获得的资源保持不放。3、不剥夺条件:一个资源被一个线程原创 2021-09-16 09:02:59 · 367 阅读 · 0 评论 -
可重入锁(递归锁)
可重入锁synchronized 和Lock都是可重入锁,也叫递归锁,即一个线程可以重复获取同一把锁是指在同一个线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁(前提,锁对象得是同一个对象),不会因为之前已经获取过还没释放而阻塞。Java中ReentrantLock和synchronized都是可重入锁,可重入锁的一个优点是可一定程度避免死锁。synchronized 是隐式锁,Lock是显式锁即synchronized 加锁解锁自动完成Lock加锁解锁要手动完成synchron原创 2021-09-16 09:02:16 · 3156 阅读 · 0 评论 -
公平锁非公平锁
在Lock锁中案例:使用非公平锁实现3个售票员卖出100张票的案例package com.dongguo.concurrent.synchronize;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/** * @author Dongguo * @date 2021/9/3 0003-10:14 * @description: 实现3个售票员卖出100张票的案原创 2021-09-16 09:01:21 · 172 阅读 · 0 评论 -
Lock接口
什么是LockLock锁实现提供了比使用同步方法和语句可以获得的更广泛的锁操作。它们允许更灵活的结构,可能具有非常不同的属性,并且可能支持多个关联的条件对象。Lock提供了比synchronized更多的功能。实现比synchronized更细粒度的加锁操作Lock与的Synchronized区别1Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问;2Lock和synchronized有一点非常大的不同,采用s原创 2021-09-16 09:00:42 · 427 阅读 · 0 评论 -
多线程锁的8种情况(经典8锁问题)
案例以synchronized为例:使用手机发短信或发邮件注意两个点:锁的对象以及锁的范围案例1先打印短信还是邮件手机有发送短信和发邮件的功能,创建两个线程分别发送短信和邮件,是先打印短信还是邮件呢?package com.dongguo.synclock;/** * @author Dongguo * @date 2021/8/24 0024-12:46 * @description: */public class ThreadDemo { public static vo原创 2021-09-16 08:58:51 · 468 阅读 · 0 评论