JUC--变量的线程安全分析

JUC–变量的线程安全分析

背景

  • JUC–变量的线程安全分析

  • 博主以黑马JUC进行学习

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

  • 如果它们没有共享,则线程安全
  • 如果它们被共享了,根据它们的状态是否能够改变,又分两种情况
    • 如果只有读操作,则线程安全
    • 如果有读写操作,则这段代码是临界区,需要考虑线程安全

局部变量是否线程安全?

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

局部变量线程安全分析

1
2
3
4
public static void test1(){
int i = 10;
i++;
}
  • 每个线程都调用了test1()方法时局部变量i,会在每个线程的栈帧内存中被创建多份,因此不存在共享
  • 方法的私有访问修饰符是有意义的,一定程度内可以保护线程安全,因为让继承它的子类不能重写方法
  • 或者加入final关键字,防止被子类继承

常见线程安全类

  • String

  • Integer

  • StringBuffer

  • Random

  • Vector

  • Hashtable

  • java.util.concurrent包下的类

  • 这里说它们是线程安全的是指,多个线程调用它们同一个实例的某个方法时,是线程安全的。也可以理解为:

    • 它们的每个方法是原子的
    • 但注意它们多个方法的组合不是原子的

线程安全类方法的组合

  • 以下例子不是线程安全的
1
2
3
4
5
Hashtable table = new Hashtable();
//线程1,线程2
if(table.get("key") == null){
table.put("key", value);
}

不可变类线程安全性

  • String、Integer 等都是不可变类,因为其内部的状态不可以改变,因此它们的方法都是线程安全的
1
2
3
4
5
6
7
8
9
10
11
public class Immutable{
private int value = 0;

public Immutable(int value){
this.value = value;
}

public int getValue(){
return this.value;
}
}
  • String类为什么要加final,因为防止被继承重写,体现了线程安全
  • 经典题目:买票问题和转账问题