Article Outline
java多线程之线程安全分析
为什么要分析线程安全?
我的理解是,多线程的前提下,只有保证线程安全,或者说,只有确保为不安全的代码部分进行加锁,才能保证代码最终的结果是正确的。
成员变量和静态变量安全分析
可以从以下几个点去考虑:
如果变量没有被共享,则线程安全
如果变量被共享了,根据变量状态是否能够改变,又分为两种情况:
- 如果只有读操作,则线程安全
- 如果有读写操作,则这段代码就是临界区,需要考虑线程安全
局部变量是否安全:
局部变量是线程安全的
局部变量引用的对象不一定是线程安全的
如果该对象没有逃离方法的作用范围,那么该变量是线程安全的
如果该对象逃离方法的作用范围,则需要考虑线程安全问题
常见的线程安全类:
- String
- Integer
- StringBuffer
- Random
- Vector
- Hashtable
- java.util.concurrent包下的类
线程安全指的是,多个线程调用它们的同一个实例的某个方法时,是线程安全的,即
它们每个方法是原子的
多个方法的组合不一定是原子的
例如:hashtable,put()方法是线程安全的,get()方法也是线程安全的,但是如果这两个方法组合成为方法块,不能保证多线程下的方法块是线程安全的。可能一个线程put()的过程中,时间片用完,切换给线程二,线程二做get()操作,会因为未放入数据就先读取数据了,这样就是线程不安全的。
不可变类的线程安全性
String、Integer都是不可变类,因为其内部的状态不可以改变,所以这些类中的方法都是线程安全的。不可变类是指,这个对象创建了就不能修改了,只能读取,如String,String的replace()方法等,是创建了新的String对象,并没有修改原来的对象。
为什么String类是final的
根据java的知识:
final 关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写
正是因为这个不能被子类重写,所以可以保证String一定是安全的。
为什么被子类重写会不安全:
因为子类如果可以重写方法,例如:子类用多线程来重写String中的方法,就可能因为多个线程的上下文切换,导致线程不安全。这类因为子类重写导致不安全的情况,经常不容易想到。