Java volatile关键字

本文探讨了Java并发编程中Volatile关键字的应用,详细解释了Volatile如何确保多线程环境下变量的可见性,以及其局限性——无法保证操作的原子性。通过具体示例展示了正确与错误的使用方式。

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

其实今天主要想说的是volatile的读写问题,首先来说一下volatile能解决什么问题,不能解决什么问题。

1. volatile能够解决线程中数据读取不一致的问题,我们知道每一个线程都有自己的线程栈,自己在自己的线程栈中存放自己线程中所需要的变量,其实可以理解成计算机硬件中的寄存器,目的是为了减少自己对内存的访问次数,那么线程栈中什么时候进行更新呢?这在线程中称为可见性,下面我们举一个错误的例子来证明线程中的数据修改的不可见性。

public class Test extends Thread{
	public boolean mark = false;
	public int i = 0;
	public void run(){
		while(!mark){
			i++;
		}
	}
	public static void main(String[] args0) throws InterruptedException{
		Test test = new Test();
		test.start();
		Thread.sleep(2000);
		test.mark = true;
		System.out.println(test.i);
	}
}

上面的例子中,我们实例化了一个线程,并且在这个线程中对mark进行检测,并对i进行++操作。然后我们将主线程休眠2s,然后对mark的值进行更改,我们希望通过这样的更改来停止线程,但是事实是我们并没有让test线程停止。这就是上面说的线程使用了自己内存中的寄存器,我们修改的主存中的数据。

如果使用了volatile效果就完全不一样,volatile的目的是为了让我们能够获取到内存中最新的数据,那么我们在更改数据的时候对于其他线程来说就是可见的。上面的例子只要把标志位添加volatile属性即可。

public class Test extends Thread{
	public volatile boolean mark = false;
	public int i = 0;
	public void run(){
		while(!mark){
			i++;
		}
	}
	public static void main(String[] args0) throws InterruptedException{
		Test test = new Test();
		test.start();
		Thread.sleep(2000);
		test.mark = true;
		System.out.println(test.i);
	}
}


2. 但是volatile并不是万能的,比如我们再进行读写操作的时候,并不能使用volatile来祈求它能够保证我们的读写操作能满足原子性原则。可以说volatile的作用就只是上面所述的保证可见性。举个例子:

public class Counter {
 
    public volatile static int count = 0;
 
    public static void inc() {
 
        //这里延迟1毫秒,使得结果明显
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
        }
 
        count++;
    }
 
    public static void main(String[] args) {
 
        //同时启动1000个线程,去进行i++计算,看看实际结果
 
        for (int i = 0; i < 1000; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Counter.inc();
                }
            }).start();
        }
 
        //这里每次运行的值都有可能不同,可能为1000
        System.out.println("运行结果:Counter.count=" + Counter.count);
    }
}
其实我们新建了1000个线程,每个线程对变量count进行++ 操作,我们希望得到的值是1000,但是并不全是。这是为什么?因为我们在进行操作的时候只是使用volatile来保证了每个线程都能够读取到内存中最新的数据,但是我们并不能避免两个线程A,B获取到的count值是相同的,如果两个线程是相同的,那么就必定会存在这样的错误。个人觉得这样的问题可以通过线程锁来进行限制。个人理解。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值