java多线程安全漫谈

1、场景

多线程安全如何定义呢?是对共享变量的修改吗?是不同步吗?设想这些场景

 1、我修了一条从自己家里到小镇上的单行道马路,自己一个人开车上下班,购物都不会阻塞。
  突然有一天,马路变成公有的了,很多车都在上面开,于是我发现经常迎面塞车。
 2、我去银行存钱,账户里本来有200w,发现有两个小妹妹,为了搭讪,让她们各自给我账户
 存100w。两个小妹妹一查我账户余额,200w,好家伙,小镇上的有钱人呀,于是忍不住和我聊起天。
 聊完,都做了一道算术题200w+100w=300w,先后往我账户上写了300w,我接过存单,
 百思不得其解,确实都给我存了100w, 算术题也没毛病,为啥我的账户上只有300w?难道撩一下妹
 就损失100w?

进入正题

上面两个场景,是引入多线程后存在两个主要问题。

  1. 线程间相互竞争有限资源,带来了死锁问题。
  2. 多个线程对于共享变量操作,执行结果不正确。
    那么简单来讲,什么是多线程安全?我们发现,在多线程环境下,有些代码,
    存在执行结果不一致的情况,并且和我们在单线程的情况下不一样,从结果上看,
    它就是不正确的。所以,理解多线程安全,不是一个非黑即白的二元模型,

多线程安全的三个特性

对于代码块,

{
    xxx
}

我们要保证它多线程环境下是安全的,有三个点要满足,就是

  1. 原子性
  2. 可见性
  3. 有序性
    为什么有这三个特性,这就要理解java线程模型,从底层剖析。理解java的线程模型,我们可以
    以从现代计算机硬件架构来对比,真的,了解硬件对对于软件开发有很好的理解作用。以cpu中
    的多核心来类比线程。在JMM中,分共享的主内存和线程私有的工作内存,所有计算操作都是
    在工作内存中完成的,然后写入主内存。真是线程中存储有副本,所以会出现不一致的情况

volatile和synchronized关键字的理解

1. volatile保证了可见性,但是在很多情况下,依然实现线程不安全的,需要使用syncrhonized同步。

为什么?因为通常我的操作都是复合操作,非原子的,比如

v = v+ 2; // 看着是一句,但是使用原子语句来拆分,则是很多句。
2. volatile修饰的变量,禁止指令重排。
3、volatile要修饰基本类型,修饰对象或者数组,这是保质了其引用的可见性

参考文章

并发编程之多线程线程安全
线程安全,原子性
《深入理解java虚拟机》

posted @ 2018-08-28 22:46  懂得了才能做一些改变  阅读(149)  评论(0编辑  收藏  举报