2 回答
![?](http://img1.sycdn.imooc.com/5333a1bc00014e8302000200-100-100.jpg)
TA贡献1827条经验 获得超9个赞
可以更仔细地查看您的代码,您所拥有的还不够。对共享字段的访问不在您的synchronized阻止范围内,因此不行。
另外,Java要求以某种方式“同步”共享内存的读取和写入。使用synchronizedkeyworld,通常意味着您需要在读取和写入上都使用它,而没有显示写入。
除此之外,用于给定的一组字段或共享内存的“锁”对于读取和写入必须是相同的锁。认真地说,volatile这里要容易得多,并且其中的APIjava.util.concurrent甚至更容易推荐。不要尝试重新发明轮子。
private static boolean flag = true; // must use 'resetFlag'
public void resetFlag() { synchronized( "lock" ) {flag = false;} }
public boolean getFlag() { synchronized( "lock" ) {return flag;} }
public void thread1() {
while ( getFlag() ){
synchronized ("lock"){
// other work
}
}
}
public static void main(String[] args) throws Exception {
Thread t1=new Thread(()->{
thread1();
});
t1.start();
Thread.sleep(1000);
resetFlag();
// The program can stop normally
}
我认为以上已作了必要的更改。
关于第二次更新:the code on my win10+JDK8 system can stop normally 是的。不能保证内存可见性,但不是禁止的。可以出于任何原因使内存可见,即使只是“偶然地”。在Intel平台上,Intel具有QPI总线,可绕过内存总线高速交换内存更新信息。但是即使可以通过软件解决,所以最好只是将同步放在需要的地方(提示:请看AtomicBoolean。)。
![?](http://img1.sycdn.imooc.com/545868b60001587202200220-100-100.jpg)
TA贡献1780条经验 获得超5个赞
由于@xTrollxDudex和@markspace提供的信息,可以从jvm级别观察循环部分中的代码,如果不存在事前关系,则可以从以下代码进行优化:
while (flag){
synchronized (lock){
// some work
}
}
至 :
if(flag){
while (true){
synchronized (lock){
//some work
}
}
}
为了确保线程可见性,我们需要避免这种优化,例如通过volatile关键字或其他同步策略。循环中同步块的外观类似于增强型volatile关键字的功能,它保证了变量前面的可见性,因此当我们第二次循环进入同步块时,可以看到最新的。所做的更改,这就是循环可以正常停止的原因。看起来不错,但这不是正确的同步方法,所以不要这样做。
添加回答
举报