栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java并发基础:变量的线程安全

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java并发基础:变量的线程安全

一、变量的线程安全分析

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

如果它们没有共享,则线程安全如果它们被共享了,根据它们的状态是否能够改变,又分两种情况:

            如果只有读操作,则线程安全
            如果有读写操作,则这段代码是临界区,需要考虑线程安全

 局部变量是否线程安全?

局部变量是线程安全的但局部变量引用的对象则未必

            如果该对象没有逃离方法的作用访问,它是线程安全的
            如果该对象逃离(return)方法的作用范围,需要考虑线程安全 

1.1 局部变量线程安全分析:

        如下所示,每个线程调用 test1() 方法时局部变量 i,会在每个线程的栈帧内存中被创建多份,因此不存在共享。

 public static void test1() {
        int i = 10;
        i++;
}

如下图所示,线程0和线程1都调用了test1()方法,他们都会创建一个test1的栈帧,这两个存在于各自线程内部的栈帧互不影响,局部变量i也是栈帧中私有的内存变量值,不会互相影响。

1.2 局部变量引用

 先看一个成员变量的例子: 

public class App 
{
    static final int THREAD_NUMBER = 2;
    static final int LOOP_NUMBER = 200;
    public static void main( String[] args ) throws InterruptedException {
        ThreadUnsafe test = new ThreadUnsafe();
        for(int i=0;i{
                test.method1(LOOP_NUMBER);
            },"Thread"+(i+1)).start();
        }
    }
}
class ThreadUnsafe{
    //共享资源
    ArrayList list = new ArrayList<>();

    public void method1(int loopNumber){
        for(int i=0;i 

        以上代码创建两个线程,同时对ThreadUnsafe对象中的ArrayList集合执行添加以及删除元素操作。该代码可能会由于线程2还未add元素,线程1remove元素而报错。

分析:

    多线程对共享资源有修改操作,产生临界区代码,会有线程安全的问题。

无论哪个线程中的method2()和method3()方法引用的都是同一个对象中的list成员变量(共享资源)

与成员变量对比的局部变量示例(局部变量没有暴漏给外部):

public class App 
{
    static final int THREAD_NUMBER = 2;
    static final int LOOP_NUMBER = 200;
    public static void main( String[] args ) throws InterruptedException {
        ThreadSafe test = new ThreadSafe();
        for(int i=0;i{
                test.method1(LOOP_NUMBER);
            },"Thread"+(i+1)).start();
        }
    }
}
class ThreadSafe{
    public void method1(int loopNumber){
        ArrayList list = new ArrayList<>();
        for(int i=0;i list ){
        list.add("1");//向集合中添加元素
    }

    private void method3(ArrayList list ){
        list.remove(0);//从集合中移除元素
    }
}

以上代码不会存在线程安全的问题,分析原因如下。

分析:

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

 二、常见线程安全类 2.1 常见线程安全类:

StringInteger 包装类StringBufferRandomVectorHashtablejava.util.concurrent包下的类

        此处说的线程安全是指,多个线程调用线程安全类的同一个实例的某个方法时,是线程安全的。可以理解为:

 他们的每个方法是原子的 但是注意:他们多个方法的组合不是原子的,如:

Hashtable table = new Hashtable();
// 线程1,线程2
if( table.get("key") == null) {
    table.put("key", value);
}

        上例中,类Hashtable类是线程安全的类,因此其每个方法都是原子的,即table.get()方法和table.put()方法单个看都是线程安全的。 但是,当两个方法组合在一起时,如两个线程1,2都执行上述代码,则不是线程安全的,如下图所示:

2.2 不可变类线程安全性

        String、Integer 等都是不可变类,因为其内部的状态不可以改变(只能读,不能改写),因此它们的方法都是线程安全的。

三、结束

        本文主要学习了变量的线程安全,其主要落脚点还是看是否共享资源并读写。
 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/711301.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号