非线程安全问题

文章讨论了Java中由于实例变量共享导致的线程安全问题,例如在多线程环境下,i--操作可能引发值的不一致。当多个线程同时访问和修改同一实例变量时,可能出现非线程安全现象。解决方案是使用`synchronized`关键字来实现同步,确保同一时间只有一个线程可以执行特定代码块,从而避免数据冲突。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

实例变量共享导致的“非线程安全问题”

如何解决这个问题?

i--与System.out.println()出现引起的“非线程安全问题”


非线程安全主要是指多个线程对同一个对象中的同一个实例变量进行操作时会出现值被更改、值不同步的情况,进而影响程序的执行流程。

实例变量共享导致的“非线程安全问题”

首先,自定义线程类中的实例变量针对其他线程可以是共享的,也可以是不共享的。

public class MyThread extends Thread{
    private int count = 5;
    public MyThread(String name){
        super();
        this.setName(name);//设置线程名称
    }
    @Override
   public void run(){
        super.run();
        while (count>0){
            count--;
            System.out.println("由"+this.currentThread().getName()+"计算,count="+count);
        }
   }
}
public class Run {
    public static void main(String[] args) {
        MyThread a = new MyThread("A");
        MyThread b = new MyThread("B");
        MyThread c = new MyThread("C");
        a.start();
        b.start();
        c.start();
    }
}

运行结果:

也就是说,一共创建了3个线程,每个线程有自己的count变量,在执行过程中自己减少自己的count变量的值。这也就表明当前情况是线程不共享的情况

public class MyThread extends Thread{
    private int count = 5;
    @Override
   public void run(){
        super.run();
            count--;
            System.out.println("由"+this.currentThread().getName()+"计算,count="+count);
   }
}
public class Run {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();

        Thread a = new Thread(myThread,"A") ;
        Thread b = new Thread(myThread,"B") ;
        Thread c = new Thread(myThread,"C") ;
        a.start();
        b.start();
        c.start();
    }
}

运行结果:

出现两个3,说明,A和B同时对count进行了处理,产生了“非线程安全”问题。

此时为什么会出现“非线程安全”问题呐?

原因在于:在某些JVM中,count--操作要分解成3步去执行:(1)获取到原有的count值。(2)计算count-1。(3)对count进行重新赋值。在这个过程中可能会被其他线程打断。也就是说,在这三个步骤中,如果有多个线程同时访问,那么很大概率会出现“非线程安全”问题。

i--操作会出现以上的问题,同理i++操作也同样会出现以上的问题。

以上出现非线程安全的情况是多个线程操作同一个对象的同一个实例变量,导致值不准确。

如何解决这个问题?

这个时候我们就需要进行上锁了。

在run方法前加上synchronized关键字,这样可以使多个线程在执行run方法时,“排队”执行。

如果一个线程要执行run方法,首先要判断run方法是否上锁,如果上锁,说明有其他线程在调用run方法,这个线程就要进行等待,等待其他线程将run方法调用结束后,才能继续调用run方法。如果没有上锁,那么直接调用。

当一个线程想要执行同步方法里面的代码,它会首先尝试去拿到这把锁,如果能拿到,那么该线程就会执行同步方法中的代码。如果不能拿到,那么这个线程就会不断的去尝试拿到这把锁,直到它成功拿到了这把锁为止。

i--与System.out.println()出现引起的“非线程安全问题”

public class MyThread extends Thread{
    private int i = 5;

    @Override
    public void run() {
        System.out.println("i="+(i--)+"  threadName="+Thread.currentThread().getName());
    }
}
public class Run {
    public static void main(String[] args) {
        MyThread run = new MyThread();
        Thread t1 = new Thread(run);
        Thread t2 = new Thread(run);
        Thread t3 = new Thread(run);
        Thread t4 = new Thread(run);
        Thread t5 = new Thread(run);


        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
    }
}

运行结果:

这里输出了2个5,也就是说,这里也出现了非线程安全问题。

println的源码:

虽然println方法在内部是synchronized同步的,但是i--操作是在进入println之前发生的,所以依旧有可能出现非线程安全问题。

这也就告诉我们:在synchronized之前执行的代码也有可能是不安全的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sunlightʊə

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值