多线程--05--变量线程安全分析(重点)

一、先说结论

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


1、如果它们没有被共享,则线程安全。
2、如果它们被共享了,根据它们的状态是否能够改变,又分两种情况:
             (1)如果只有读操作,则线程安全
            (2) 如果有读写操作,需要考虑线程安全问题(读时可能会读到中间结果,所以有读写时,读也要考虑线程安全)

1.2 局部变量是否线程安全?


1、基本数据类型的局部变量是线程安全的。
2、引用类型的局部变量,要看该对象有没有逃离方法的作用范围,

             (1)如果对象仅在方法内创建、使用、消亡,则是线程安全的;

            (2)如果一个对象由外部传入,或者传出外部,则需要考虑线程安全问题(外部仅读,线程安全;外部有读写--如果不考虑同步机制的话,会存在线程安全问题)

举例见本文第三章--举例1

二、常见的线程安全类

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

线程安全类的方法是线程安全的(final修饰的类为不可变类,不可变类的方法也是线程安全的)

线程安全类的单个方法是线程安全的,但是多个方法的组合不一定是线程安全的。

三、举例分析(重点)

3.1 举例1

package com.fuping3.safe;

public class StringBuilderTest {
    int num = 10;

    //s1的声明方式是线程安全的(只在方法内部用了)
    public static void method1(){
        //StringBuilder类型本身是线程不安全
        StringBuilder s1 = new StringBuilder();
        s1.append("a");
        s1.append("b");
        //...
    }

    //sBuilder的操作过程:是线程不安全的(作为参数传进来,可能被其它线程操作)
    public static void method2(StringBuilder sBuilder){
        sBuilder.append("a");
        sBuilder.append("b");
        //...
    }

    //s1的操作:是线程不安全的(有返回值,可能被其它线程操作)
    public static StringBuilder method3(){
        StringBuilder s1 = new StringBuilder();
        s1.append("a");
        s1.append("b");
        return s1;
    }

    //s1的操作:是线程安全的(s1自己消亡了,最后返回的s1.toString是新建的的一个对象)
    /*
     *StringBuilder类中toString源码
     *   public String toString() {
     *       return new String(this.value, 0, this.count);
     *   }
     */
    public static String method4(){
        StringBuilder s1 = new StringBuilder();
        s1.append("a");
        s1.append("b");
        return s1.toString();
    }
}

3.2 举例2:

/**
 *前置知识--HttpServlet默认是单例的
 */
public class MyServlet extends HttpServlet{
    Map<String,Object> map=new HashMap<>();  //线程不安全
    final String S2="XXX";                   //线程安全,因为final修饰的String类型,值不可被改变
    Date D1=new Date();                      //线程不安全
    final Date D2=new Date();                //线程不安全,因为虽然是被final修饰的常量,但仅是地址不可变,值仍可变
}

3.3 举例3:

分析:

1、MyServlet 继承自HttpServlet是单例的,多线程调用时,userService对象只有一个。

2、userService中的count成员变量,由于被共享读写,所以是线程不安全的

3.4 举例4

分析:

1、MyAspect类的@Scope默认没写,所以是单例的。

2、start成员变量,由于被共享读写,所以是线程不安全的

3.5 举例5

分析:

1、MyServlet 继承自HttpServlet是单例的,多线程调用时,userService对象只有一个,也为单例。

2、userService对象只有一个,所以userDao对象也只有一个。

3、由于UserDaoImpl--update方法中局部变量sql、conn作用范围都仅在update方法中,所以update方法是线程安全的,所以整体是线程安全的

3.6 举例6:

分析:

1、MyServlet 继承自HttpServlet是单例的,多线程调用时,userService对象只有一个,也为单例。

2、userService对象只有一个,所以userDao对象也只有一个。

3、由于UserDaoImpl的成员变量conn,在多线程环境下会被共享读写,所以整体是线程不安全的。

3.7 举例7

springMVC三层结构中线程安全性写法:

1、每次调用,都新建一个service层对象,或dao层对象,从而不共享成员变量或类变量;

2、变量作用范围都在方法内部;

3、只读共享变量

分析:

1、MyServlet 继承自HttpServlet是单例的,多线程调用时,userService对象只有一个,也为单例。

2、userService对象只有一个,但是userServiceImpl--update方法每次被调用时,都会new一个userDao对象,所以以userDao对象是多个。

3、UserDaoImpl的成员变量conn,虽然在UserDaoImpl--update方法中会被修改,但是conn并未被共享(userDao对象是多个),所以整体是线程安全的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值