我找到了一段似乎线程饥饿的代码。下面是一个简化的示例。这是饥饿的例子吗?线程不终止的原因是什么?

注意:将 sleep 时间更改为1有时会导致终止。注释掉的Thread.yield()将解决问题(对我来说)。

public class Foo {

    public static boolean finished = false;

    public static void main(String[] args) {

          Runnable worker = new Runnable() {

                 @Override
                 public void run() {

                      try {
                           Thread.sleep(10);
                      } catch (InterruptedException e) {
                          // TODO Auto-generated catch block
                          e.printStackTrace();
                      }

                      finished = true;
                 }
            };

            new Thread(worker).start();

            while (!finished) {
//          Thread.yield();
        }
    }
}

最佳答案

您可能需要了解Java内存模型。多线程不仅涉及交错线程的行为,它还涉及多个线程。它是关于一个线程到另一个线程的 Action 可见性。

这个问题的根本在于面对并发性时需要进行积极的优化:确保线程之间的内存一致性的任何机制都是昂贵的,并且大部分(大部分)数据不会在线程之间共享。因此,默认情况下,没有显式标记为volatile或未受锁保护的数据将被视为线程本地的(当然,没有严格的保证)。

在您的情况下,finished是一个这样的变量,如果它使运行时令人满意,则可以将其视为线程本地的。它确实令人满意,因为

while (!finished);

循环可以重写为
if (!finished) while (true);

如果您在循环中进行了任何重要的工作,它的性能会更好一些,因为不会不必要地重复读取finished,从而可能会破坏整个CPU缓存行。

上面的讨论足以回答您的直接问题“这是饥饿吗”:循环未完成的原因不是饥饿,而是无法看到其他线程的写操作。

09-25 23:12