HOME/Articles/

java多线程之线程安全分析

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中的方法,就可能因为多个线程的上下文切换,导致线程不安全。这类因为子类重写导致不安全的情况,经常不容易想到。