Java:空的while循环

12

我正在编写一个程序,其中while循环以以下方式执行:

  1. 主线程进入while循环。
  2. while循环中不会发生任何事情。
  3. 线程将一直停留在while循环中,直到条件得到满足。
  4. 另一个线程运行将满足该条件的函数。

这里是一个例子:

while(path != null);

这个类中还有另一个函数会将路径设置为null,一旦发生这种情况,主线程应该退出此循环。另一个函数在另一个线程中被调用。

然而,即使将路径设置为null,主线程仍然没有退出循环。有什么建议吗?

代码:

try 
 { 
  for (Node n:realpath) 
    { 
      Thread.sleep(100); 
      actor.walk(n); 
     }
    Thread.sleep(100); 
 } 
 catch (InterruptedException ex) 
  { 
    Logger.getLogger(VNScreen.class.getName()).log(Level.SEVERE, null, ex); 
  } 
  realpath.clear(); 
  path = null;

if(path == null)
    System.out.println("NULLED PATH");

2
路径在哪里定义?它可能需要是“易失的”。 - wrschneider
2
如果您发布完整的代码,人们将更能够找到您的问题。 - ewok
路径是类中的私有属性。上述两个函数也在该类中。 - Abraham Miguel Espiritu
有人已经替你处理了,@AbrahamMiguelEspiritu,但是将来最好编辑您的原始问题以添加代码。这样更易读。 - Paul
通过记录路径为空来证明。我不相信线程执行。 - emory
我之前做过这件事,系统确实将路径注册为 null。 - Abraham Miguel Espiritu
4个回答

13

繁忙等待非常昂贵。我会这样做:

Object LOCK = new Object(); // just something to lock on

synchronized (LOCK) {
    while (path != null) {
        try { LOCK.wait(); }
        catch (InterruptedException e) {
            // treat interrupt as exit request
            break;
        }
    }
}

当你将 path 设为 null 时,只需调用

synchronized (LOCK) {
    LOCK.notifyAll();
}

如果两段代码在同一个对象中,您可以只对 this 进行同步。


非常感谢,您认为这个lock变量应该放在调用wait的类中还是在调用notifyAll的类中? - Halil İbrahim Oymacı
1
@HalilİbrahimOymacı - 我认为这并不重要,只要变量对需要它的所有代码都是可访问的。它甚至可以是一个独立的单例对象在自己的类中。 - Ted Hopp

6

不需要使用底层的wait/notify方法,并且为了避免使用volatile时的忙等待,可以使用CountDownLatch。由于只有一个事件需要等待,因此应该实例化计数器:

CountDownLatch latch = new CountDownLatch(1);

将你的 while (path != null) 替换为:

latch.await();

在您的主代码中,只需要这样做:
path = somePath;
latch.countDown();

4
您可能需要将path声明为volatile。如果未声明变量为volatile,编译器则可以在寄存器中缓存其值,因此对该值的任何更改都将不被识别。
但总的来说,这种代码风格非常糟糕(除了一些低级实模式之外)。当您的while循环正在运行时,它会消耗100%的CPU,所以任何其他过程要更改path的值可能永远无法执行,并且执行日常任务(如维护通信链接或更新鼠标光标位置)的其他进程也将不会执行。
最好使用基于事件/消息/信号量的通信方式,以便您的“循环”在继续之前等待信号。 "可接受"的是利用某种延迟,例如Thread.sleep,这样您只需每隔几毫秒“轮询”变量即可。您还可以尝试Thread.yield,但这有点靠运气并且在各种环境中不能产生可靠的结果。

-1

主线程不会退出循环,因为在 while 条件中没有任何内容,并且检查条件非常快速,而且 while 循环中的变量没有改变。您有两种方法来解决这个问题: 1- 在 while 循环中等待短时间,例如 5 毫秒。

    while(path != null){
     try{
       Thread.currentThread().sleep(50);
     }catch(){
       //do nothing
     }
    }

将路径变量定义为volatile:

  volatile String path;

Java内存模型并不保证你的第一个解决方案会起作用。如果你使用-server参数运行它,甚至很可能不起作用,因为条件将被优化掉,并转换为while(true) - assylias

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接