我拥有以下代码来测试 volatile 。 bEnd
和nCount
被定义为易失性。
nCount = 0, bEnd = false
Writer线程将设置
nCount = 100, bEnd = true
Reader线程读取这些可变对象并进行打印。我认为,基于Java先发生顺序, volatile确保当bEnd = true时nCount = 100 。但是有时程序会显示以下内容:
main thread done.
thread Reader running ...
thread Writer running ...
SharedData nCount = 0, bEnd = false
thread Writer bEnd = true
thread Reader nCount = 0, bEnd = true
thread Reader nCount = 100, bEnd = true
thread Reader nCount = 100, bEnd = true
thread Reader done.
阅读器如何获取“ nCount = 0,bEnd = true” ???
以下代码在Windows10上运行,jdk1.8.0_131
public class HappensBeforeWithVolatile {
public static void main(String[] args) {
Thread threadWriter = new Thread(new Writer());
Thread threadReader = new Thread(new Reader());
threadWriter.start();
threadReader.start();
System.out.println("main thread done.");
}
}
class Writer implements Runnable {
@Override
public void run() {
System.out.println("thread Writer running ...");
SharedData.nCount = 100;
// System.out.println("thread Writer nCount = 100");
SharedData.bEnd = true;
System.out.println("thread Writer bEnd = true");
}
}
class Reader implements Runnable {
@Override
public void run() {
System.out.println("thread Reader running ...");
System.out.println("thread Reader nCount = " + SharedData.nCount + ", bEnd = " + SharedData.bEnd);
System.out.println("thread Reader nCount = " + SharedData.nCount + ", bEnd = " + SharedData.bEnd);
if (SharedData.nCount == 0 && SharedData.bEnd) {
System.out.println("thread Reader CODE REORDER !!!");
}
System.out.println("thread Reader nCount = " + SharedData.nCount + ", bEnd = " + SharedData.bEnd);
System.out.println("thread Reader done.");
}
}
class SharedData {
volatile public static boolean bEnd = false;
volatile public static int nCount = 0;
static {
System.out.println("SharedData nCount = " + nCount + ", bEnd = " + bEnd);
}
}
答案 0 :(得分:3)
volatile确保bEnd = true时nCount = 100
从技术上讲,是的。但是读者并没有原子地阅读它们。因此它可能会打印<?xml version="1.0" encoding="UTF-8"?><process version="9.0.000-BETA">
<context>
<input/>
<output/>
<macros/>
</context>
<operator activated="true" class="process" compatibility="9.0.000-BETA" expanded="true" name="Process">
<process expanded="true">
<operator activated="true" class="subprocess" compatibility="9.0.000-BETA" expanded="true" height="82" name="Subprocess" width="90" x="112" y="34">
<process expanded="true">
<operator activated="true" class="retrieve" compatibility="9.0.000-BETA" expanded="true" height="68" name="Retrieve Iris" width="90" x="45" y="34">
<parameter key="repository_entry" value="//Samples/data/Iris"/>
</operator>
<operator activated="true" class="declare_missing_value" compatibility="9.0.000-BETA" expanded="true" height="82" name="Declare Missing Value" width="90" x="179" y="34">
<parameter key="attribute_filter_type" value="single"/>
<parameter key="attribute" value="a1"/>
<parameter key="mode" value="expression"/>
<parameter key="expression_value" value="a1 <5"/>
</operator>
<operator activated="true" class="select_attributes" compatibility="9.0.000-BETA" expanded="true" height="82" name="Select Attributes" width="90" x="380" y="34">
<parameter key="attribute_filter_type" value="subset"/>
<parameter key="attributes" value="a2|a1"/>
</operator>
<connect from_op="Retrieve Iris" from_port="output" to_op="Declare Missing Value" to_port="example set input"/>
<connect from_op="Declare Missing Value" from_port="example set output" to_op="Select Attributes" to_port="example set input"/>
<connect from_op="Select Attributes" from_port="example set output" to_port="out 1"/>
<portSpacing port="source_in 1" spacing="0"/>
<portSpacing port="sink_out 1" spacing="0"/>
<portSpacing port="sink_out 2" spacing="0"/>
</process>
</operator>
<operator activated="true" class="generate_attributes" compatibility="9.0.000-BETA" expanded="true" height="82" name="Generate Attributes" width="90" x="447" y="34">
<list key="function_descriptions">
<parameter key="a1_new" value="if(a1==MISSING_NUMERIC, a2,a1)"/>
</list>
</operator>
<connect from_op="Subprocess" from_port="out 1" to_op="Generate Attributes" to_port="example set input"/>
<connect from_op="Generate Attributes" from_port="example set output" to_port="result 1"/>
<portSpacing port="source_input 1" spacing="0"/>
<portSpacing port="sink_result 1" spacing="0"/>
<portSpacing port="sink_result 2" spacing="0"/>
<description align="center" color="yellow" colored="false" height="181" resized="true" width="529" x="275" y="126">With the expression parser more complex statements can be defined. In this case:<br>if(a1==MISSING_NUMERIC, a2,a1)<br/><br/>meaning that if the value of attribute a1 is missing, it will be replaced by the value of a2 otherwise the value of a1 is kept.<br/><br/>Instead of creating a new attribute the old one can also be overwritten<br/><br></description>
</process>
</operator>
</process>
。
这里是一个例子:
nCount = 0 and bEnd = true
nCount 0
nCount = 100
bEnd = true
thread Writer bEnd = true
答案 1 :(得分:1)
您的整个示例有点瑕疵。要测试之前发生的情况,您需要测试后续操作,即使bEnd
易变而nCount
不是易失,然后将示例简化为:
static class Reader implements Runnable {
@Override
public void run() {
while (true) {
if (SharedData.bEnd) {
System.out.println(SharedData.nCount);
break;
} else {
System.out.println("Not yet seen as true");
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
}
}
}
}
static class Writer implements Runnable {
@Override
public void run() {
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1000));
SharedData.nCount = 100;
SharedData.bEnd = true;
}
}
这将始终(至少在这种情况下)输出100
。正确的解释是,如果Reader
线程看到volatile变量的Write
线程的更新,它将看到在此之前所做的所有事情,因此100
。