java多线程(并发)夯实之路-线程安全分析深入浅出

回顾

多个线程对共享资源进行写操作时,会发生上下文切换,造成线程安全问题。

一段代码块中如果存在对共享资源的多线程读写操作,则称这段代码区为临界区。

多个线程在临界区内执行,代码执行序列不同导致结果无法预测,称为发生了竞态条件。

变量的线程安全分析

1.成员变量和静态变量是否线程安全?

只有当它们被共享,并且不只有读,还有写操作时,会发生临界区的竞态条件,需要考虑线程安全问题

2.局部变量是否线程安全?

局部变量是线程安全的

局部变量引用的对象未必,如果该对象逃离方法的作用范围,则需要考虑线程安全问题

局部变量线程安全分析

每个线程调用某一方法中的局部变量时,会在每个线程的栈帧内存中创建多份,变量并不共享

如图

局部变量引用对象如果是共享的,可能发生线程安全问题,例子如下

将list改为局部变量,list就不是共享资源了,线程就是安全的了

上述代码中将private改为了public

这时如果有其他线程调用method2和method3也不会发生安全问题

但是如果为这个类添加子类,子类覆盖method2或method3方法,即

新线程和原来的线程有共享资源,就有了线程安全问题

因此可以用private修饰method2和method3,并且用final修饰method1来防止子类重写方法,发生线程安全问题

可见private和final可以提供安全,这也是开闭原则中的闭

常见的线程安全类

String,Integer,StringBuffer,Random,Vector,Hashtable,java.util.concurrent包下的类(JUC)多个线程调用它们同一个实例的方法时是线程安全的。

它们的每个方法是原子的(如Hashtable中的put方法是用synchronzied来修饰的),但它们的多

个方法的组合不是原子的。例:

不可变类线程安全性

String,Integer等都是不可变类,其内部状态不可改变(如String的substring方法会复制原有字符串来创建一个新字符串,并没有改变其属性)

下图中D2也不是线程安全的,D2的引用对象不可变,但Date内属性可以变

以下代码也不是线程安全的,update方法内为临界区

以下代码也不是线程安全的,这是单例,start需要被共享,进行读写操作时会发生线程安全问题,可以把使用环绕通知把start变为局部变量

以下代码是线程安全的(推荐使用这种方法),没有成员变量一般都是安全的,如果把conn变为成员变量就会发生线程安全问题

以下代码也是线程安全的

以下代码不是线程安全的,foo的行为不确定,可能导致不安全的发生,称为外星方法

注意闭合原则,String类设为final,防止了子类重写String类中方法,破坏不可变性

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值