java多线程安全漫谈
1、场景
多线程安全如何定义呢?是对共享变量的修改吗?是不同步吗?设想这些场景
1、我修了一条从自己家里到小镇上的单行道马路,自己一个人开车上下班,购物都不会阻塞。
突然有一天,马路变成公有的了,很多车都在上面开,于是我发现经常迎面塞车。
2、我去银行存钱,账户里本来有200w,发现有两个小妹妹,为了搭讪,让她们各自给我账户
存100w。两个小妹妹一查我账户余额,200w,好家伙,小镇上的有钱人呀,于是忍不住和我聊起天。
聊完,都做了一道算术题200w+100w=300w,先后往我账户上写了300w,我接过存单,
百思不得其解,确实都给我存了100w, 算术题也没毛病,为啥我的账户上只有300w?难道撩一下妹
就损失100w?
进入正题
上面两个场景,是引入多线程后存在两个主要问题。
- 线程间相互竞争有限资源,带来了死锁问题。
- 多个线程对于共享变量操作,执行结果不正确。
那么简单来讲,什么是多线程安全?我们发现,在多线程环境下,有些代码,
存在执行结果不一致的情况,并且和我们在单线程的情况下不一样,从结果上看,
它就是不正确的。所以,理解多线程安全,不是一个非黑即白的二元模型,
多线程安全的三个特性
对于代码块,
{
xxx
}
我们要保证它多线程环境下是安全的,有三个点要满足,就是
- 原子性
- 可见性
- 有序性
为什么有这三个特性,这就要理解java线程模型,从底层剖析。理解java的线程模型,我们可以
以从现代计算机硬件架构来对比,真的,了解硬件对对于软件开发有很好的理解作用。以cpu中
的多核心来类比线程。在JMM中,分共享的主内存和线程私有的工作内存,所有计算操作都是
在工作内存中完成的,然后写入主内存。真是线程中存储有副本,所以会出现不一致的情况
volatile和synchronized关键字的理解
1. volatile保证了可见性,但是在很多情况下,依然实现线程不安全的,需要使用syncrhonized同步。
为什么?因为通常我的操作都是复合操作,非原子的,比如
v = v+ 2; // 看着是一句,但是使用原子语句来拆分,则是很多句。
2. volatile修饰的变量,禁止指令重排。
3、volatile要修饰基本类型,修饰对象或者数组,这是保质了其引用的可见性
参考文章
并发编程之多线程线程安全
线程安全,原子性
《深入理解java虚拟机》
日进有功