Does the volatile keyword guarantee the latest value to be read by a reader thread? If not, what is its use?

huangapple go评论76阅读模式
英文:

Does the volatile keyword guarantee the latest value to be read by a reader thread? If not, what is its use?

问题

请参考以下代码。

Shared.java

class Shared
{
    public volatile int i = 0;
}

CreateThread.java

class CreateThread
{
    public static void main(String[] args) throws InterruptedException
    {
        Shared s = new Shared();
        MyThread t1 = new MyThread(s);
        t1.start();
        while(s.i!=7)
            System.out.println(s.i);
    }
}

MyThread.java

class MyThread extends Thread
{
    Shared s = null;
    MyThread(Shared s)
    {
        this.s = s;
    }    
    public void run()
    {
        for(int j=0; j<15; j++)
        {
            s.i = s.i+1;
        }
        System.out.println("Thread Going to Stop");
    }
}

如果不允许新线程睡眠,那么似乎主线程无法获取变量 s.i 的所有值。因为在这种情况下,我们会得到以下输出。

0
15
15
15
..
..
..

如果允许新线程睡眠,那么似乎主线程可以获取变量 s.i 的所有值。因为在这种情况下,我们会得到以下输出。

0
0
..
1
1
..
2
2
..
3
3
..
4
4
..
直至 6

从上面的输出可以清楚地看出,如果新线程不进入睡眠状态,新线程会在主线程有机会读取它之前多次更改 s.i 的值。

如果我将程序更改为:

Shared.java

class Shared
{
    public /*volatile*/ boolean i = false;
}

MyThread.java

class MyThread extends Thread
{
    Shared s = null;
    MyThread(Shared s)
    {
        this.s = s;
    }    
    public void run()
    {
        s.i = true;
        System.out.println("New Value of s.i " + s.i);
        try
        {
            Thread.sleep(10000);
        }
        catch(Exception e){}
        System.out.println("Thread Going to Stop");
    }
}

CreateThread.java

class CreateThread
{
    public static void main(String[] args) throws InterruptedException
    {
        Shared s = new Shared();
        MyThread t1 = new MyThread(s);
        t1.start();
        while(s.i == false)
            System.out.println(s.i);
        System.out.println(s.i + " Main Stopped");
    }
}

输出:

false
New Value of s.i true
true Main Stopped
Thread Going to Stop

似乎数据即使不是 volatile,也会立即对线程可用。

以下是我的问题。

  1. volatile 关键字是否保证阅读线程读取的是最新值?
  2. 如果 volatile 关键字通过不将数据保存在 CPU 寄存器中来将数据保存在内存中,我们将获得哪些好处?您能给出一个实际的工作示例来证明 volatile 的好处吗?
英文:

Please refer to the following codes.

Shared.java

class Shared
{
	public volatile int i = 0;
}

CreateThread.java

class CreateThread
{
	public static void main(String[] args) throws InterruptedException
	{
		Shared s = new Shared();
		MyThread t1 = new MyThread(s);
		t1.start();
		while(s.i!=7)
 			System.out.println(s.i);
	}
}

MyThread.java

class MyThread extends Thread
{
	Shared s = null;
	MyThread(Shared s)
	{
		this.s = s;
	}	
	public void run()
	{
		for(int j=0; j&lt;15; j++)
		{
	/*		try
			{
				Thread.sleep(1000);
			}
			catch(Exception e){}*/
			s.i = s.i+1;
		//	System.out.println(&quot;New Value of s.i &quot;+s.i);
	/*		try
			{
				Thread.sleep(1000);
			}
			catch(Exception e){}*/
		}
		System.out.println(&quot;Thread Going to Stop&quot;);
	}
}

If the new thread is not allowed to sleep, then it seems that the main thread cannot find all the values of the variable s.i. Because in this case, we are getting the following output.

0
15
15
15
..
..
..

If the new thread is allowed to sleep, then it seems that the main thread can find all the values of the variable s.i. Because in this case, we are getting the following output.

0
0
..
1
1
..
2
2
..
3
3
..
4
4
..
upto 6

From the above output, it is clear that if the new thread does not go into the sleep state, the new thread is changing the value of s.i in memory several times before the thread main gets a chance to read it.

If I change the program as:

Shared.java

class Shared
{
	public /*volatile*/ boolean i = false;
}

MyThread.java

class MyThread extends Thread
{
	Shared s = null;
	MyThread(Shared s)
	{
		this.s = s;
	}	
	public void run()
	{
	
			s.i = true;
			System.out.println(&quot;New Value of s.i &quot;+s.i);
			try
			{
				Thread.sleep(10000);
			}
			catch(Exception e){}
		System.out.println(&quot;Thread Going to Stop&quot;);
	}
}

CreateThread.java

class CreateThread
{
	public static void main(String[] args) throws InterruptedException
	{
		Shared s = new Shared();
		MyThread t1 = new MyThread(s);
		t1.start();
		while(s.i==false)
 			System.out.println(s.i);
		System.out.println(s.i+&quot; Main Stopped&quot;);
	}
}

Output:

C:\Users\gyan0\OneDrive\Desktop&gt;java CreateThread
false
New Value of s.i true
true Main Stopped
Thread Going to Stop

It seems that the data, even though it is not volatile, is becoming immediately available to the thread.

Following are my questions.

  1. Does the volatile keyword guarantee the latest value to be read by a reader thread?
  2. What the benefits we would get if volatile keyword saves a data in memory by not saving it in CPU Register? Can you give a practical working example proving the benefits of the volatile?

答案1

得分: 1

易失性变量在读操作和随后的写操作之间创建一个happens before边缘。因此,在同步顺序中,读操作将看到在它之前的最近的写操作。

举个反例来说明。想象一下,如果i不是volatile的:

while(s.i==false)
        System.out.println(s.i);

由于在循环中s.i没有改变,编译器可能会将对i的读取提升出循环,就像这样。

boolean r = s1.i;
while(r == false)
        System.out.println(r);

现在,读取操作将永远不会在循环中看到已写入的值。

甚至可以进一步优化这段代码:

boolean r = s1.i;
if(r==false){
    while(true)
        System.out.println(false);
}
英文:

The volatile variable creates a happens before edge between a read and a subsequent write. So the read will see the most recent write before it in the synchronization order.

To give you a counter example. Imagine i would not be volatile:

while(s.i==false)
        System.out.println(s.i);

Because s.i isn't changed in the loop, the compiler could hoist the read of i out of the loop like this.

boolean r = s1.i;
while(r == false)
        System.out.println(r);

And now the read will never see the written value in the loop.

This code could even be further optimized:

boolean r = s1.i;
if(r==false){
    while(true)
        System.out.println(false);
}

答案2

得分: 0

关于您的第二个问题,所有线程都有各自的本地缓存,这些缓存可能不会立即与主内存进行更新。使用volatile关键字可以确保该值得到更新,从而使线程能够获取更新后的值。您可以在下面的示例中查看:

https://dzone.com/articles/java-multi-threading-volatile-variables-happens-be-1

英文:

Regarding your question 2, all the threads have its local cache which may not be immediately updated to/from main memory. Using volatile, it ensures that the value is updated and threads can get the updates values. you can check this below example:

https://dzone.com/articles/java-multi-threading-volatile-variables-happens-be-1

huangapple
  • 本文由 发表于 2020年8月21日 14:55:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/63517923.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定