【Java基础-并发编程】-变量的线程安全分析

一、变量的线程安全分析

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

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

1.2 局部变量是否线程安全

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

1.3 局部变量是线程安全的

public static void test1(){
        int i=10;     //i是局部变量,线程安全的
        i++;
    }

1.4 成员变量线程不安全

class ThreadUnsafe{
    ArrayList<String> list = new ArrayList<>();
    //多线程调用method1方法,ArrayList.add和ArrayList.remove的线程不安全。因为都会操作属性size,
    // 可能会导致add时size值未加成功,但多次remove
    public void method1(int loopNumber){    
        
        for (int i = 0; i < loopNumber; i++) {
            method2();
            method3();
        }
    }
    private void method2(){list.add("1");}
    private void method3(){list.remove(0);}
}

分析: 

1.5 将1.4中的成员变量改成局部变量,线程安全

class ThreadSafe{
    public void method1(int loopNumber){
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < loopNumber; i++) {
            method2(list);
            method3(list);
        }
    }
    private void method2(ArrayList<String> list){list.add("1");}
    private void method3(ArrayList<String> list){list.remove(0);}
}

分析:

  • list是局部变量,每个线程调用时都会创建其不同实例,没有共享
  • 而method2的参数是从method1中传递过来的,与method1中引用同一个对象

二、常见线程安全类

2.1 常见线程安全类

  • String
  • Integer
  • StringBuffer
  • Random
  • Vector
  • Hashtable
  • java.util.concurrent包下的类

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

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

如下线程安全类方法的组合是线程不安全的

 2.2 不可变线程安全性

String、Integer等都是不可变类,因为其内部的属性不可以改变,因此它们的方法都是线程安全的。

三、实例分析

3.1 实例1

class MyServlet extends HttpServlet {
    //线程不安全
    Map<String,String> map = new HashMap<>();
    //线程安全
    String s1="...";
    //线程安全
    final  String s2="...";
    //线程不安全
    Date d1 = new Date();
    //线程不安全
    final Date d2 = new Date();
    
    public void doGet(HttpServletRequest request, HttpServletResponse response){
        //使用上述变量
    }
}

3.2 实例2

public class MyServlet extends HttpServlet {
    //线程不安全
    private UserService userService = new UserServiceImpl();
    
    public void doGet(HttpServletRequest request, HttpServletResponse response){
        userService.update();
    }
}

public  class  UserServiceImpl implements  UserService{
    //记录调用次数
    private int count=0;
    public void update(){
        //...
        count++;
    }
    
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值