多线程中 静态变量,普通变量(实例变量),局部变量,静态方法,普通方法 的线程安全问题


多线程中 静态变量,普通变量(实例变量),局部变量,静态方法,普通方法 的线程安全问题

类型是否安全存储位置解释
静态变量线程不安全方法区静态变量为类所持有,为所有对象共享,全局只有一份,一旦静态变量被修改,其他对象均对修改可见,所以线程不安全
普通变量(实例变量)单例模式下不安全
非单例模式下安全
普通变量为这个对象实例私有,在虚拟机的堆中分配,单例模式下,所有的操作都是针对这一个对象的属性,就会像静态变量那样,一旦被某个线程修改后,对其他的线程都可见,所以非线程安全。如果每个线程执行都是一个新的对象,每个对象间的属性就不会产生影响,所以是线程安全的。
局部变量线程安全每个线程执行的时候,会把局部变量保存在各自的栈帧的工作内存中,线程之间不共享不可见,所以不存在线程安全问题
静态方法引用静态变量不安全
没有引用静态变量安全
方法区如果引用了静态变量,情形就如果静态变量的结果(只能存在引用静态变量,静态方法和属性可以被非静态引用,但是静态不能引用非静态,因为静态方法在类加载的时候就初始化了,除了final类型),不引用就是一个普通的方法,只不过加上静态修饰后,在整个JVM中只会保存一份。
普通方法是否引用了变量,以及是否单例运行单例情况下,如果没有引用内部的变量,线程安全的,非单例的情况下,引不引入变量都是安全的。

测试静态变量

所有的线程操作一个变量,线程之间不安全

public class StaticTest implements Runnable {

    // 此处定义一个静态变量
    private static int i;

    /**
     * 在线程运行的时候,如果正常的情况下应该输出,2,10
     * 如果证明线程不安全,即其他线程修改了别的线程正常运行的值
     * 会出现A线程把i修改为5,即将执行i*2=10的时候,其他线程B把i修改为2,使结果输出为4
     * A线程把i赋值为2,即将执行输出i=2的时候,线程B把i修改为5,使结果输出为5
     * 无论输出4,5都是线程不安全的体现
     */
    @Override
    public void run() {
        i=2;
        System.out.println("["+Thread.currentThread().getName()+"] 当前静态变量i="+i);
        i=5;
        System.out.println("["+Thread.currentThread().getName()+"] 当前静态变量i="+i*2);
    }

    public static void main(String[] args) {
        StaticTest test = new StaticTest();
        for(int i=0;i<1000;i++){
            new Thread(test,"线程"+i).start();
        }
        /**
         * [线程245] 当前静态变量i=2
         * [线程245] 当前静态变量i=4
         * [线程246] 当前静态变量i=2
         * [线程172] 当前静态变量i=10
         * [线程177] 当前静态变量i=5
         * [线程177] 当前静态变量i=10
         * [线程179] 当前静态变量i=5
         * [线程179] 当前静态变量i=10
         * [线程171] 当前静态变量i=2
         * [线程171] 当前静态变量i=10
         * [线程180] 当前静态变量i=5
         */
    }
}

测试普通变量 单例

所有的线程一同操作,一个对象中的一个属性,会产生线程争用的情况,所以线程不安全

public class NormalTest implements Runnable {

    // 此处定义一个变量
    private int i;

    /**
     * 在线程运行的时候,如果正常的情况下应该输出,2,10
     * 如果证明线程不安全,即其他线程修改了别的线程正常运行的值
     * 会出现A线程把i修改为5,即将执行i*2=10的时候,其他线程B把i修改为2,使结果输出为4
     * A线程把i赋值为2,即将执行输出i=2的时候,线程B把i修改为5,使结果输出为5
     * 无论输出4,5都是线程不安全的体现
     */
    @Override
    public void run() {
        i=2;
        System.out.println("["+Thread.currentThread().getName()+"] 当前变量i="+i);
        i=5;
        System.out.println("["+Thread.currentThread().getName()+"] 当前变量i="+i*2);
    }

    public static void main(String[] args) {
        NormalTest test = new NormalTest();
        for(int i=0;i<1000;i++){
            new Thread(test,"线程"+i).start();
        }
        /**
         * [线程190] 当前变量i=10
         * [线程187] 当前变量i=5
         * [线程187] 当前变量i=10
         * [线程944] 当前变量i=2
         * [线程945] 当前变量i=4
         * [线程949] 当前变量i=2
         */
    }
}

测试普通变量 非单例

每一个对象里面的属性都是线程单独拥有,不会存在互相争用的情况,线程安全

public class NormalTest implements Runnable {

    // 此处定义一个变量
    private int i;

    /**
     * 在线程运行的时候,如果正常的情况下应该输出,2,10
     */
    @Override
    public void run() {
        i=2;
        System.out.println("["+Thread.currentThread().getName()+"] 当前变量i="+i);
        i=5;
        System.out.println("["+Thread.currentThread().getName()+"] 当前变量i="+i*2);
    }

    public static void main(String[] args) {
        for(int i=0;i<1000;i++){
            new Thread(new NormalTest(),"线程"+i).start();
        }
        /**
         * [线程190] 当前变量i=10
         * [线程187] 当前变量i=10
         * [线程944] 当前变量i=2
         * [线程949] 当前变量i=2
         */
    }
}

测试静态方法

静态方法只能引用静态变量和静态方法,引用后等于静态变量的处理

public class NormalTest implements Runnable {

    // 此处定义一个静态变量
    private static int i;

    /**
     * 在线程运行的时候,如果正常的情况下应该输出,2,10
     * 如果证明线程不安全,即其他线程修改了别的线程正常运行的值
     * 会出现A线程把i修改为5,即将执行i*2=10的时候,其他线程B把i修改为2,使结果输出为4
     * A线程把i赋值为2,即将执行输出i=2的时候,线程B把i修改为5,使结果输出为5
     * 无论输出4,5都是线程不安全的体现
     */
    @Override
    public void run() {
        add();
    }

    public static void add() {
        i=2;
        System.out.println("["+Thread.currentThread().getName()+"] 当前变量i="+i);
        i=5;
        System.out.println("["+Thread.currentThread().getName()+"] 当前变量i="+i*2);
    }

    public static void main(String[] args) {
        NormalTest t = new NormalTest();
        for(int i=0;i<1000;i++){
            new Thread(t,"线程"+i).start();
        }
        /**
         * [线程161] 当前变量i=2
         * [线程161] 当前变量i=4
         * [线程251] 当前变量i=2
         * [线程794] 当前变量i=10
         * [线程818] 当前变量i=5
         * [线程818] 当前变量i=10
         */
    }
}

测试普通方法

普通方法引用变量后,单例情况下线程不安全,多例下线程安全
没有引用变量,线程安全

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值