下面的代码是一直循环,但是如果把29行的synchronized(lock)注释去掉,程序就立刻退出来,能解释为什么吗?
我查了一些资料,“当读线程获取锁的时候,强制从主内存读取。写进程释放锁,会强制刷新到主内存”但是我的InnerStop 没有获取锁?哪位大侠能解释为什么吗
package current;
//主类
class TestJMM {
public static void main(String[] args) {
for(int i=0;i<1;i++){
InnerRun jmm=new InnerRun();
jmm.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();

new InnerStop(jmm).start();
}


}
}
//工作线程
class InnerRun extends Thread{
boolean stop ;
StringBuffer sb=new StringBuffer();
Object lock=new Object();
int i=0;
@Override
public void run() {
while(!stop){
//synchronized(lock){
i++;
//}
}
}

public void stopMe() {
stop = true;
}
}
//停止线程
class InnerStop extends Thread{
InnerRun jmm=null;
public InnerStop(InnerRun jmm){
this.jmm=jmm;
}
@Override
public void run() {
jmm.stopMe();
}
}

解决方案 »

  1.   

    @Enchanter,   和这个时间没关系吧,我改成5秒10秒都是一样的结果
      

  2.   

    Changes to fields made by one thread are guaranteed to be visible to other threads only under the following conditions:
    1.A writing thread releases a synchronization lock and a reading thread subsequently acquires that same synchronization lock.In essence, releasing a lock forces a flush of all writes from working memory employed by the thread, and acquiring a lock forces a (re)load of the values of accessible fields
    2.As a thread terminates, all written variables are flushed to main memory. For example, if one thread synchronizes on the termination of another thread using Thread.join, then it is guaranteed to see the effects made by that threadThe memory model guarantees that, given the eventual occurrence of the above operations, a particular update to a particular field made by one thread will eventually be visible to another. But eventually can be an arbitrarily long time. Long stretches of code in threads that use no synchronization can be hopelessly out of synch with other threads with respect to values of fields. In particular, it is always wrong to write loops waiting for values written by other threads unless the fields are volatile or accessed via synchronization个人想法:重点在于那个while循环,你无非是想测试在innerrun线程里是否看得到innerstop线程对stop变量的更改,目前你的方式是while循环不断去获取,这个死循环可能导致stop变量一直没有得到刷新(从主存到线程工作内存),你可以换一种放肆来测试:class InnerRun extends Thread {
        boolean stop;
        StringBuffer sb = new StringBuffer();
        Object lock = new Object();
        int i = 0;    @Override
        public void run() {
            System.out.println(stop);
            
            long start = System.currentTimeMillis();
            while (System.currentTimeMillis() - start < 2000) {  // 这个时间要大于主线程的睡眠时间
                
            }
            
            System.out.println(stop); // 打印出来的是true,当然理论上也不是一定打印true,因为我们说的保证可见性指的是立即可见,但是即使我们不刻意的去保证可见性,它其实最终也是可见的,只不过这个最终的时长是不确定(但往往短到你感觉不出来)而已,实际的运行往往很难测出这种情况
        }    public void stopMe() {
            stop = true;
        }
    }总的来说,while死循环使得stop变量没有机会得到更新另外,你的这个程序的逻辑就不太对(或许你是刻意这么写的。。),你要保证的是stop变量的可见性,你应该在读写stop变量时加synchronize或者用volatile修饰stop,而不是对i变量的操作加同步
      

  3.   


    1.加synchronize或volatile 肯定可以保证同步的。现在我是为了探索在不给变量枷锁的情况下,变量的同步策略。
    2.“死循环可能导致stop变量一直没有得到刷新“?为什么?我觉得是因为stop变量没有刷新导致一直死循环
    3,我的目录是在没有给变量枷锁的情况下,什么情况下可以看到stop线程的变量?是随机还是什么?你贴出的一段英文是Doug Lea的论文观点,我也是看了他的这个,有点疑惑。我们都知道:读线程要想拿到stop线程变量必须有两步:1,stop线程刷新变量到主内存,2.读线程强制从主内存读取。根据Doug Lea 的观点,我的代码:
    public void run() {
    while(!stop){
    synchronized(lock){
    for(int i=1;i<100;i++){
      if (Math.log10(i) < 0)
      throw new AssertionError();
    }
    }
    }
    } 为什么就能读取到stop线程的值,而去掉syncronized就读取不到
      

  4.   


    1.加synchronize或volatile 肯定可以保证同步的。现在我是为了探索在不给变量枷锁的情况下,变量的同步策略。
    2.“死循环可能导致stop变量一直没有得到刷新“?为什么?我觉得是因为stop变量没有刷新导致一直死循环
    3,我的目录是在没有给变量枷锁的情况下,什么情况下可以看到stop线程的变量?是随机还是什么?你贴出的一段英文是Doug Lea的论文观点,我也是看了他的这个,有点疑惑。我们都知道:读线程要想拿到stop线程变量必须有两步:1,stop线程刷新变量到主内存,2.读线程强制从主内存读取。根据Doug Lea 的观点,我的代码:
    public void run() {
    while(!stop){
    synchronized(lock){
    for(int i=1;i<100;i++){
      if (Math.log10(i) < 0)
      throw new AssertionError();
    }
    }
    }
    } 为什么就能读取到stop线程的值,而去掉syncronized就读取不到
    我觉得这个和synchronize没有太大关系,即使这么写:public void run() {
    while(!stop){
    Thread.sleep(1);
    }
    }
    } 这个循环也是能结束的。我猜测是不是有这样的可能:在循环里读取变量时线程总是从工作内存读,
    1.加synchronize或volatile 肯定可以保证同步的。现在我是为了探索在不给变量枷锁的情况下,变量的同步策略。
    2.“死循环可能导致stop变量一直没有得到刷新“?为什么?我觉得是因为stop变量没有刷新导致一直死循环
    3,我的目录是在没有给变量枷锁的情况下,什么情况下可以看到stop线程的变量?是随机还是什么?你贴出的一段英文是Doug Lea的论文观点,我也是看了他的这个,有点疑惑。我们都知道:读线程要想拿到stop线程变量必须有两步:1,stop线程刷新变量到主内存,2.读线程强制从主内存读取。根据Doug Lea 的观点,我的代码:
    public void run() {
    while(!stop){
    synchronized(lock){
    for(int i=1;i<100;i++){
      if (Math.log10(i) < 0)
      throw new AssertionError();
    }
    }
    }
    } 为什么就能读取到stop线程的值,而去掉syncronized就读取不到

    看下这个链接
    https://help.semmle.com/wiki/display/JAVA/Spin+on+field
      

  5.   

    还有   https://en.wikipedia.org/wiki/Loop-invariant_code_motion