JUC详解
一、Java多线程 -- JUC包源码分析1 -- CAS/乐观锁
乐观锁其实就是不加锁,用CAS + 循环重试,实现多个线程/多个客户端,并发修改数据的问题
使用AtomicStampedReference类下的
public boolean compareAndSet(V expectedReference, //旧值 V newReference, //新值 int expectedStamp, //旧版本号 int newStamp //新版本号)
方法可实现原子性的CAS
–上面的atomicRef.compareAndSet(..)的第一个参数,传入的是一个ReferenceIntegerPair对象,它里面包含了2个字段:值 + 版本号。这也就意味着,它同时比较了值和版本号。
– 值不等,则肯定被其他线程改过了,不用再比较版本号,cas提交失败;
值相等,再比较版本号,如果版本号也相等,则说明真的没有被改过,cas提交成功;
值相等,版本号不等,则就是出现了ABA,cas提交失败。
二、Java多线程 -- JUC包源码分析2 -- Copy On Write/CopyOnWriteArrayList/CopyOnWriteArraySet
CopyOnWrite,
顾名思义:就是在Write的时候,不直接Write源数据,而是把数据Copy一份出来改,改完之后,再通过悲观锁或者乐观锁的方式写回去。
CopyOnWrite的主要目的是实现“写”加锁,“读”不加锁,从而提高并发度。在上面例子中,CopyOnWriteArrayList使用了CopyOnWrite + 悲观锁; NumberRange使用了CopyOnWrite + 乐观锁。
CopyOnWriteArraySet就是用Array实现的一个Set,保证所有元素都不重复。其内部就是封装的一个CopyOnWriteArrayList
三、Java多线程 -- JUC包源码分析3-- volatile/final语义
-volatile应用1 – 内存可见性 – JMM内存模型
线程A,线程B有各自的local内存。在把变量从主内存读到自己的工作内存,修改之后,不一定会立即写入主存,因此另一个线程不可见。
要保证上述案例可以完全正确执行,需要在变量前加volatile。
volatile变量可以保证:每次对该变量的写,必定刷回到主存;每次对该变量的读,必定从主存读取。从而可以保证,一个线程对共享变量的写,对其他线程可见。
-volatile应用2 – 原子性
由于JMM并不要求对一个64位的long/double型的变量写入具有原子性,在32位的机器上,对一个long型变量的写入,可能会分成高32位,低32位2次写入。此时,另一个线程去读取时,可能读到“写了一半”的无效值!
要解决上述问题,可以加锁,也可以加volatile关键字。
可见,在对单个变量的读写中,volatile变量起到了锁同样的作用。
也正因为如此,在AtomicInteger/AtomicLong中,其get()/set()函数,都未加锁,却是线程安全的!!
-volatile应用3 – 构造函数逸出/DCL问题(Double Checking Locking)
线程安全的单例模式中,有一种经典写法,即DCL(Doule Checking Locking),如下所示:
public class Sington
{
private static Sington instance;
public static Sington getInstance()
{
if(instance == null) //DCL
{
synchronized(Sington.class)
{
if(instance == null)
instance = new Instance(); //有问题的代码!!!
}
}
return instance;
}
上述的new Instance(),底层可以分为3个操作: 分配内存,在内存上初始化成员变量,把instance指向内存。
这3个操作,可能重排序,即先把instance指向内存,再初始化成员变量。
此时,另外一个线程就会拿到一个未完全初始化的对象。这时直接访问里面的成员变量,就可能出错。而这就是典型的“构造函数溢出”问题。
要解决此问题,只要在instance前加volatile就可以了!
当然,还有另外1种经典的线程安全的单例模式 – 基于类加载器的方案
public class Instance
{
private static class InstanceHolder
{
public static Instance instance = new Instance();
}
public static Instance getInstance()
{
return InstanceHolder.instance;
}
}
-final应用1 – 避免构造函数重排序

答案是:a, b 未必一定等于1,2。因为这里的i, j都是非volatile变量,线程A的重排序,可能使得i, j的赋值,在构造函数之后执行!!也就是说,线程B拿到obj的时候,obj的i, j变量可能赋值还未完成!
解决办法是:给i, j 加上final,final的语义: 保证final变量的初始化,一定在构造函数返回之前完成!
-final应用2 – CopyOnWrite
在上1篇 NumberRange例子中,我们看到lower, power都是final类型,这也确保了lower, power只可能被赋值1次。后续要想再改变值,只能拷贝一份出来改!
所以,通常应用CopyOnWrite的地方,也会相应的使用final!
-atomic数组/volatile数组/final数组/ 


-指令重排序,happen before语义
从上述各种案例可以看出,问题主要出在“指令重排序”上。
为什么要指令重排序呢?
从程序员角度来讲,最好是不要有任何的指令重排,这样程序最容易理解;但从CPU和编译器角度,希望在不改变单线程程序语义的情况下,尽可能的重排序,最大程度的提高执行效率。
而对于多线程程序,因为重排序导致的线程之间的不同步,则由程序员自己处理!
volatile和final的底层原理,就是一定程度上禁止重排序,从而实现多线程程序的同步。
四、Java多线程 -- JUC包源码分析4 -- 各种锁与无锁
未看懂。。。。。。。。
五、Java多线程 -- JUC包源码分析5 -- Condition/ArrayBlockingQueue/LinkedBlockingQueue/Deque/PriorityBl
参考:http://blog.csdn.net/chunlongyu/article/category/6399716
JUC详解的更多相关文章
- JUC详解--【Foam番茄】
1.什么是JUC java.util 工具包 业务:普通的线程代码 Thread Runnable 没有返回值,效率相比于 Callable 相对较低! 2.线程和进程 进程:一个程序,QQ.exe ...
- 跟着阿里p7一起学java高并发 - 第19天:JUC中的Executor框架详解1,全面掌握java并发核心技术
这是java高并发系列第19篇文章. 本文主要内容 介绍Executor框架相关内容 介绍Executor 介绍ExecutorService 介绍线程池ThreadPoolExecutor及案例 介 ...
- java高并发系列 - 第20天:JUC中的Executor框架详解2之ExecutorCompletionService
这是java高并发系列第20篇文章. 本文内容 ExecutorCompletionService出现的背景 介绍CompletionService接口及常用的方法 介绍ExecutorComplet ...
- JUC中的AQS底层详细超详解
摘要:当你使用java实现一个线程同步的对象时,一定会包含一个问题:你该如何保证多个线程访问该对象时,正确地进行阻塞等待,正确地被唤醒? 本文分享自华为云社区<JUC中的AQS底层详细超详解,剖 ...
- (转)Java并发包基石-AQS详解
背景:之前在研究多线程的时候,模模糊糊知道AQS这个东西,但是对于其内部是如何实现,以及具体应用不是很理解,还自认为多线程已经学习的很到位了,贻笑大方. Java并发包基石-AQS详解Java并发包( ...
- 【1】AQS详解
概述: 它内部实现主要是状态变量state和一个FIFO队列来完成,同步队列的头结点是当前获取到同步状态的结点,获取同步状态state失败的线程,会被构造成一个结点加入到同步队列尾部(采用自旋CAS来 ...
- Disruptor 详解 二
Disruptor 的大名从很久以前就听说了,但是一直没有时间:看完以后才发现其内部的思想异常清晰,很容易就能前移到其他的项目,所以仔细了解一下还是很有必要的这.篇博客将主要从源码角度分析,Disru ...
- Mysql高手系列 - 第9篇:详解分组查询,mysql分组有大坑!
这是Mysql系列第9篇. 环境:mysql5.7.25,cmd命令中进行演示. 本篇内容 分组查询语法 聚合函数 单字段分组 多字段分组 分组前筛选数据 分组后筛选数据 where和having的区 ...
- 最强Java并发编程详解:知识点梳理,BAT面试题等
本文原创更多内容可以参考: Java 全栈知识体系.如需转载请说明原处. 知识体系系统性梳理 Java 并发之基础 A. Java进阶 - Java 并发之基础:首先全局的了解并发的知识体系,同时了解 ...
随机推荐
- 剑指Offer 36. 两个链表的第一个公共结点 (链表)
题目描述 输入两个链表,找出它们的第一个公共结点. 题目地址 https://www.nowcoder.com/practice/6ab1d9a29e88450685099d45c9e31e46?tp ...
- 自动化测试-16.selenium数据的分离之Excel的使用
前言 在自动化测试中,单纯写得测试脚本,数据往往是写死的,这样会给程序的可扩展性降低,以及成本的增加,将程序和数据进行剥离有利于提高代码的执行效率,提升工作量,因此将数据写入到Excel文件中,前置条 ...
- js··事件捕捉
给一个元素绑定事件,普通写法是 obj.onclick=function(){} 这就相当于给obj的onclick属性赋值是一个道理. obj.onclick=function(){} 这种写法有一 ...
- js中常用的内置对象
Arguments 函数参数集合 arguments[ ] 函数参数的数组 Arguments 一个函数的参数和其他属性 Arguments.callee 当前正在运行的函数 Argument ...
- js有哪些变态的语法?
JS这个语言好是好,但是很多时候写起来太丑了,每次看大牛的代码的时候,妈妈都问我为什么跪着读代码,随着 ES 2015的普及我们可以写出很多可读性强且漂亮的代码,那么接下来就带着大家一块学习一下可以把 ...
- dos2unix 批量转化文件
在windows和linux双平台下开发,同时也用git作为同步工具,但前期没有注意,导致很多文件使用windows下的换行符CRLF 参考资料了解dos2unix可以转化格式. 但有个问题,虽然可以 ...
- vue+elementui按需引入
转载自以下网址,仅作备忘之用:https://www.cnblogs.com/lwj820876312/p/9169457.html 基于Vue的Ui框架 饿了么公司基于vue开的的vue的Ui组件库 ...
- iuplua test on luaforwindows
SW https://github.com/rjpcomputing/luaforwindows/releases Steps Install lua for windows write a bat ...
- 问题 Windows7VMware14安装虚拟机时出现 此主机不支持虚拟化实际模式。需要具备 Intel“VMX 不受限客户机”功能才能在 Intel 处理器上运行此虚拟机。 模块“CPUIDEarly”启动失败。
问题 Windows7VMware14安装虚拟机时出现 此主机不支持虚拟化实际模式.需要具备 Intel“VMX 不受限客户机”功能才能在 Intel 处理器上运行此虚拟机. 模块“CPUIDEarl ...
- forward reference前向引用,gloal values and local values全局变量和局部变量,recursive function递归函数
1.全局变量与局部变量练习 1 # -*- coding: UTF-8 -*- 2 def bar(): 3 print('from bar') 4 def foo(): 5 print('from ...