java 多线程 volatile bug?

白马秋 发布于 2017/03/07 10:55
阅读 614
收藏 3

试了volatile作用,发现结果B线程的i值是从1直接到3,讲道理不应该获得A线程之后的结果(i=2)到3吗?

````

package com.zhoupq.multiThread.Volatile;

public class VolatileDemo implements Runnable
{

    static volatile int    i    = 1;

    @Override
    public void run()
    {
        System.out.println(Thread.currentThread().getName() + ": " + i + ", "
                + (++i));
    }

    public static void main(String[] args)
    {
        Thread t1 = new Thread(new VolatileDemo(), "A");
        Thread t2 = new Thread(new VolatileDemo(), "B");
        Thread t3 = new Thread(new VolatileDemo(), "C");
        Thread t4 = new Thread(new VolatileDemo(), "D");

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

加载中
0
f
face2016

volatile保证了数据的可见性,但是不保证原子性

244395026
244395026
回复 @白马秋 : volatile本来就不是用来处理并发情况下的,只能用在根据它修饰的变量进行判断处理,但是不能让它本身进行处理
白马秋
白马秋
回复 @盛开距离 : 明白了,多谢。
uglybaby
uglybaby
回复 @白马秋 : volatile 不能解决并发计算的问题,并发计算可以用Atomicxxxx来保证原子性
f
face2016
回复 @白马秋 : volatile的非原子性:线程工作内容中的值从主内存中直接加载,一旦加载完成,就不会再产生对应的变化。JVM保证的是从主内存中加载到线程工作内存中的值是最新的,但是无法保证原子性。 volatile解决的是变量读时的可见性问题,无法保证原子性。
白马秋
白马秋
你是说 ++i 操作对volatile来讲,不保证原子性?如果这样,岂不是连volatile也难逃并发
0
白马秋
白马秋

多次运行,也出现了预期的结果:

0
烟雨三月
烟雨三月

+ i 和+(++i)是两条指令,会发生这种情况:

假设当前i为1,线程A执行+i,线程B执行+i,然后线程A执行+(++i),这时i=2,然后线程B执行+(++i),这时i=3,线程A输出(1, 2),线程B输出(1, 3)。

白马秋
白马秋
A、B线程将i从主内存加载进入线程本地内存的时候,因为使用了volatile,所以,i对于多线程不应该是可见的吗?也就是说,A、B线程中i的初始值不会是一样的,因为A中,i=2,B获得i的值也为2,至少不会是1。我是这么理解的。
0
notreami
notreami
public class VolatileTest extends Thread {
    //不加入volatile,则status没有被置为false
    private boolean status = true;

    @Override
    public void run() {
        int i = 0;
        while (status) {
            i++;
        }
        System.out.println("finish loop,i=" + i);
    }

    public boolean isStatus() {
        return status;
    }

    public void setStatus(boolean status) {
        this.status = status;
    }

    public static void main(String[] args) throws InterruptedException {
        VolatileTest thread = new VolatileTest();
        thread.start();
        Thread.sleep(300);
        thread.setStatus(false);
        System.out.println("wait loop");
        System.out.println(thread.isStatus());
        thread.join();
        System.out.println("finish main");
        System.out.println(thread.isStatus());
    }
}

想起曾今的一个面试题

zjg23
zjg23
回复 @白马秋 : 什么情况下会出现死循环?
白马秋
白马秋
死循环 好例子啊
0
爱吃大肉包
爱吃大肉包

一句话,volatile并不具备原子性

白马秋
白马秋
多谢
0
w
wanggod

引用来自“白马秋”的评论

多次运行,也出现了预期的结果:

public class VolatileDemo implements Runnable {

	static volatile int i = 1;
	
	static CyclicBarrier b = new CyclicBarrier(4);

	@Override
	public void run() {
		try {
			b.await();
		} catch (InterruptedException | BrokenBarrierException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + ": " + i + ", " + (++i));
	}

	public static void main(String[] args) {
		Thread t1 = new Thread(new VolatileDemo(), "A");
		Thread t2 = new Thread(new VolatileDemo(), "B");
		Thread t3 = new Thread(new VolatileDemo(), "C");
		Thread t4 = new Thread(new VolatileDemo(), "D");

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

}

加入屏障,一起起跑,就很容易重现
C: 1, 3
D: 4, 5
A: 3, 4
B: 1, 2

 

白马秋
白马秋
等待4个一起跑,基本不会出现预期结果 哈哈
爱吃大肉包
爱吃大肉包
用atomic效果更好
0
官万人员
官万人员

volatile并不具备原子性

白马秋
白马秋
可见性 非原子性 多谢
0
我_承宇
我_承宇

你看看字节码文件就明白啦,++i,是两条指令

白马秋
白马秋
说的是
0
蓝风970655147
蓝风970655147

恭喜你, 发现了一个bug 

白马秋
白马秋
哪是bug呀 我只是在吸引眼球 各路大神围观
0
首席猎头美少女
首席猎头美少女

欢迎关注微信公众号“猎头小曹的杂货铺”,美少女会再微信公众号定期更新最一手的职位信息和公司信息,这些资料都是通过采访内部员工才知道的,啊,,,,毕竟美少女是一位走心的猎头,大家快来关注,,等你们~~

返回顶部
顶部