博客
关于我
多线程系列:线程安全及不可变性
阅读量:100 次
发布时间:2019-02-26

本文共 1686 字,大约阅读时间需要 5 分钟。

当多个线程同时访问同一个资源,并且其中的一个或者多个线程对这个资源进行了写操作,才会产生竞态条件。多个线程同时读同一个资源不会产生竞态条件。

我们可以通过创建不可变的共享对象来保证对象在线程间共享时不会被修改,从而实现线程安全。如下示例:

01 public class ImmutableValue{
02     private int value = 0;
03  
04     public ImmutableValue(int value){
05         this.value = value;
06     }
07  
08     public int getValue(){
09         return this.value;
10     }
11 }

请注意ImmutableValue类的成员变量value是通过构造函数赋值的,并且在类中没有set方法。这意味着一旦ImmutableValue实例被创建,value变量就不能再被修改,这就是不可变性。但你可以通过getValue()方法读取这个变量的值。

如果你需要对ImmutableValue类的实例进行操作,可以通过得到value变量后创建一个新的实例来实现,下面是一个对value变量进行加法操作的示例:

01 public class ImmutableValue{
02     private int value = 0;
03  
04     public ImmutableValue(int value){
05         this.value = value;
06     }
07  
08     public int getValue(){
09         return this.value;
10     }
11  
12     public ImmutableValue add(int valueToAdd){
13         return new ImmutableValue(this.value + valueToAdd);
14     }
15 }

请注意add()方法以加法操作的结果作为一个新的ImmutableValue类实例返回,而不是直接对它自己的value变量进行操作。

引用不是线程安全的!

重要的是要记住,即使一个对象是线程安全的不可变对象,指向这个对象的引用也可能不是线程安全的。看这个例子:

01 public void Calculator{
02     private ImmutableValue currentValue = null;
03  
04     public ImmutableValue getValue(){
05         return currentValue;
06     }
07  
08     public void setValue(ImmutableValue newValue){
09         this.currentValue = newValue;
10     }
11  
12     public void add(int newValue){
13         this.currentValue = this.currentValue.add(newValue);
14     }
15 }

Calculator类持有一个指向ImmutableValue实例的引用。注意,通过setValue()方法和add()方法可能会改变这个引用。因此,即使Calculator类内部使用了一个不可变对象,但Calculator类本身还是可变的,因此Calculator类不是线程安全的。换句话说:ImmutableValue类是线程安全的,但使用它的类不是。当尝试通过不可变性去获得线程安全时,这点是需要牢记的。

要使Calculator类实现线程安全,将getValue()、setValue()和add()方法都声明为同步方法即可。(java会保证对引用的读写是原子的,但add方法中有对currentValue的再次引用,也就相当于i++之类的语法,所以还需要做同步,只有volatile是不行的。)

原文地址:

http://ifeve.com/thread-safety-and-immutability/

转载地址:http://qncy.baihongyu.com/

你可能感兴趣的文章
MySQL与Oracle的数据迁移注意事项,另附转换工具链接
查看>>
mysql丢失更新问题
查看>>
MySQL两千万数据优化&迁移
查看>>
MySql中 delimiter 详解
查看>>
MYSQL中 find_in_set() 函数用法详解
查看>>
MySQL中auto_increment有什么作用?(IT枫斗者)
查看>>
MySQL中B+Tree索引原理
查看>>
mysql中cast() 和convert()的用法讲解
查看>>
mysql中datetime与timestamp类型有什么区别
查看>>
MySQL中DQL语言的执行顺序
查看>>
mysql中floor函数的作用是什么?
查看>>
MySQL中group by 与 order by 一起使用排序问题
查看>>
mysql中having的用法
查看>>
MySQL中interactive_timeout和wait_timeout的区别
查看>>
mysql中int、bigint、smallint 和 tinyint的区别、char和varchar的区别详细介绍
查看>>
mysql中json_extract的使用方法
查看>>
mysql中json_extract的使用方法
查看>>
mysql中kill掉所有锁表的进程
查看>>
mysql中like % %模糊查询
查看>>
MySql中mvcc学习记录
查看>>