Java并发编程实战(三)-线程的共享

1.可见性

为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制。

如果缺乏同步机制,其他线程可能读取不到一个线程对变量的写操作,更可能由于存在重排序的现象导致其余线程产生一些“奇怪”的现象。

重排序导致:在缺乏足够的同步机制的程序中,要想对内存操作的执行顺序进行判断,几乎无法得到正确的结果

关于重排序可见:

http://www.infoq.com/cn/articles/java-memory-model-2

1.1失效数据

1 public class MutableInteger{
2      private int value;
3 
4      public int get() {return value;}
5      public void set(){this,.value=value;}               
6 }

一个线程set,而另外一个执行get方法线程可能得不到value的新值,需要把get和set方法改成同步方法,如下:

1 public class MutableInteger{
2       private int value;
3  
4       public synchronized int get() {return value;}
5       public synchronized void set(){this,.value=value;}               
6  }

如果仅对set方法进行同步,get方法仍然会看到失效值

1.2非原子的64位操作

失效值只是之前某个线程设定的值,而不是一个随机值,这种安全性保证也成为最低安全性,最低安全性适用于绝大多数变量,除了非volatile类型的64位数值变量(double和long)。这类数值变量将读写操作分解为两个32位的操作,即使不考虑失效数据问题,页,在多个线程中使用共享可变long和double的变量也是不安全的,除非使用关键字volatile关键字或锁保护起来。

1.3加锁与可见性

在访问某个共享可变变量时要求所有线程在同一个锁上同步,就是为了确保某个线程写入该变量的值对于其他线程是可见的,否则,就有可能读到一个失效值。

加锁的含义不仅仅局限于互斥行为,还包括内存的可见性。为了确保所有线程都能看到共享变量的最新值,所有执行读操作或写操作的线程都必须在同一个锁上同步。

1.4Volatile变量

volatile变量只能确保变量的可见性并不保证原子性。因此通常用于某个操作完成,发生中断或者状态的标志。

使用volatile变量的条件:

(1)对变量的写入操作不依赖变量的当前值,或者只有单个线程更新变量的值

(2)该变量不会与其他状态变量一起纳入不变性的条件中

(3)在访问该变量时不需要加锁

2.发布与逸出

“发布”是指使对象能够在当前作用域之外的的代码中使用。

“逸出”是指某个不应该发布的对象被发布了。

3.线程封闭

3.1Ad-hoc线程封闭

维护线程封闭性的职责完全有程序实现来承担

3.2栈封闭

3.3ThreadLocal类

4.不变性

不可变对象一定是线程安全的。

当满足一下条件时,对象才是不可变的:

(1)对象创建以后其状态就不能改变

(2)对象的所有域都是final类型

(3)对象是正确创建的(在对象的创建期间,this引用没有逸出)

4.1Final域

5.安全发布

Java并发编程实战(三)-线程的共享,布布扣,bubuko.com

Java并发编程实战(三)-线程的共享

上一篇:Mininet python API StaticFlowPusher 基于网段写flow


下一篇:Java并发编程之线程管理(高级线程同步9)