ok,我贴上代码: import java.util.concurrent.TimeUnit; public class StopThread { private static boolean stopRequested; public static void main( String[] args ) throws InterruptedException{ Thread backgroudThread = new Thread( new Runnable(){ public void run() { int i = 0; while ( !stopRequested ) { i++; } } });
The problem is that in the absence of synchronization, there is no guarantee as to when, if ever, the background thread will see the change in the value of stop- Requested that was made by the main thread. In the absence of synchronization, it’s quite acceptable for the virtual machine to transform this code:while (!done){ i++; }into this code:if (!done) { while (true){ i++; } } This optimization is known as hoisting, and it is precisely what the HotSpot server VM does. The result is a liveness failure: the program fails to make progress. One way to fix the problem is to synchronize access to the stopRequested field.
这篇文章真挺好的,有些地方都很简练地说明和总结了double-checked locking这个现象 关于why it doesn't work The first reason it doesn't workThe most obvious reason it doesn't work it that the writes that initialize the Helper object and the write to the helper field can be done or perceived out of order. Thus, a thread which invokes getHelper() could see a non-null reference to a helper object, but see the default values for fields of the helper object, rather than the values set in the constructor.If the compiler inlines the call to the constructor, then the writes that initialize the object and the write to the helper field can be freely reordered if the compiler can prove that the constructor cannot throw an exception or perform synchronization.Even if the compiler does not reorder those writes, on a multiprocessor the processor or the memory system may reorder those writes, as perceived by a thread running on another processor. 他这里只是提到关于constructor的Out-of-order writes现象,还是没有点到为什么最终得到的会是那个为构建的只有默认值的对象non-null reference,虽然可能也不是太难想到~此时另外一个线程却可以得到一个非空未初始化对象,下面这个链接有较详细说明:http://www.ibm.com/developerworks/java/library/j-dcl.html
主要是取决于jvm的优化,作者说的情况是下面这种(模拟作者jvm优化后的效果),这样第一个线程只会判断一次标志位,所以控制不了 public class Test0702 { private static boolean stop; /** * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { // TODO Auto-generated method stub Thread bt = new Thread(new Runnable(){ public void run() { // TODO Auto-generated method stub int i=0; // while(!stop) // { // i++; // System.out.println(i); // } if(!stop) while(true) { i++; System.out.println(i); } }
import java.util.concurrent.TimeUnit;
public class StopThread {
private static boolean stopRequested;
public static void main( String[] args ) throws InterruptedException{
Thread backgroudThread = new Thread( new Runnable(){
public void run() {
int i = 0;
while ( !stopRequested )
{
i++;
}
}
});
backgroudThread.start();
TimeUnit.SECONDS.sleep( 1 );
stopRequested = true;
System.out.print( "as" );
}
}
On my machine, however, the program never terminates: the background
thread loops forever!
”
线程之间如果未同步是有可能造成关于stopRequested变量不及时共享的
to when, if ever, the background thread will see the change in the value of stop-
Requested that was made by the main thread. In the absence of synchronization,
it’s quite acceptable for the virtual machine to transform this code:while (!done){
i++;
}into this code:if (!done) {
while (true){
i++;
}
}
This optimization is known as hoisting, and it is precisely what the HotSpot server
VM does. The result is a liveness failure: the program fails to make progress. One
way to fix the problem is to synchronize access to the stopRequested field.
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
关于why it doesn't work
The first reason it doesn't workThe most obvious reason it doesn't work it that the writes that initialize the Helper object and the write to the helper field can be done or perceived out of order. Thus, a thread which invokes getHelper() could see a non-null reference to a helper object, but see the default values for fields of the helper object, rather than the values set in the constructor.If the compiler inlines the call to the constructor, then the writes that initialize the object and the write to the helper field can be freely reordered if the compiler can prove that the constructor cannot throw an exception or perform synchronization.Even if the compiler does not reorder those writes, on a multiprocessor the processor or the memory system may reorder those writes, as perceived by a thread running on another processor. 他这里只是提到关于constructor的Out-of-order writes现象,还是没有点到为什么最终得到的会是那个为构建的只有默认值的对象non-null reference,虽然可能也不是太难想到~此时另外一个线程却可以得到一个非空未初始化对象,下面这个链接有较详细说明:http://www.ibm.com/developerworks/java/library/j-dcl.html
public class Test0702 { private static boolean stop;
/**
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
Thread bt = new Thread(new Runnable(){ public void run() {
// TODO Auto-generated method stub
int i=0;
// while(!stop)
// {
// i++;
// System.out.println(i);
// }
if(!stop)
while(true)
{
i++;
System.out.println(i);
}
}
});
bt.start();
java.util.concurrent.TimeUnit.SECONDS.sleep(1);
stop = true;
}}