【问题标题】:Main thread stops in an infinite loop主线程无限循环停止
【发布时间】:2014-04-10 13:35:50
【问题描述】:

我有一个小程序向用户展示一个 GUI 来选择一个文件,然后程序会根据文件内容执行并相应地显示结果。

这是在主线程中运行的循环(main() 方法):

do {
    args = fg.getFile();
} while (!fg.started);

fg.started 是一个布尔变量,当用户选择一个文件并按下“开始”按钮时设置为 true。

但是,除非我将随机任务放入循环中,否则这不起作用:

do {
    args = fg.getFile();
    System.out.println("");
} while (!fg.started);

这行得通。

谁能解释一下这是为什么?

我知道一个涉及 Thread 类的解决方案,包括 notify() 和 wait() 等,但现在我只是对此感到好奇。

【问题讨论】:

标签: java multithreading loops user-interface


【解决方案1】:

fg.started 是一个布尔变量,当用户选择一个文件并按下“开始”按钮时设置为 true。

但是,除非我将随机任务放入循环中,否则这不起作用:

这是因为两个线程在没有内存同步的情况下访问started 字段。您没有显示fg.started 的定义,但我怀疑您需要确保它是volatile。您也可以考虑切换到AtomicBoolean。这是Java tutorial about memory synchronization。

volatile boolean started;

多线程应用程序的问题是程序的某些部分可以在具有自己本地内存缓存的不同处理器中运行。每当线程修改或访问共享字段时,都需要显式同步以确保它们不只是查看字段的本地缓存值。

当您添加 System.out.println(...) 时它会起作用,因为 PrintStream 的方法是同步的,因此您正在添加间接内存同步。

让 getFile() 同步修复它,谢谢。小心解释为什么? :)

因为,就像 System.out.println(...) 一样,您正在添加间接同步。

【讨论】:

  • 啊,太好了。现在我明白为什么 sysouting 起作用了 :)
  • 您应该放松一下,您似乎认为积分是世界上最重要的事情。如果您想通过使最佳答案获得最高分来帮助社区,请尽量不要表现得像您希望自己获得最高分
  • 我很放松。 :-) 这与@hewo 无关。这是关于后代的正确答案。这是关于有益的经验。这是为了纠正无效的答案。
  • "...添加间接同步。" Java 语言规范承诺,如果线程 A 更新一个字段然后释放一些锁,然后线程 B 稍后获取相同的锁,那么线程 B 应该能够看到更新的字段值。一种简单的实现方法是,释放锁会刷新本地缓存,获取锁会使本地缓存失效。根据体系结构和 JVM 实现,仅线程 A 获取和释放锁以使更新(最终)对线程 B 可见就足够了。
【解决方案2】:

您应该同步fg的访问,否则可能会发生这种情况:

  • Thread1 可能会激活,访问并因此阻止fg,然后暂停。
  • Thread2 变为活动状态,无法访问fg 并立即停用。
  • Thread1 再次处于活动状态,完成任务并立即重新访问fg,然后暂停。
  • Thread2 变得活跃并且......该死! fg又被锁了!

如果您需要有关并发/并行执行的帮助/说明,请参阅Oracle - Syncronization 了解信息。

【讨论】:

  • 使 getFile() 同步修复它,谢谢。小心解释为什么? :)
  • @hewo 编辑了我的答案,希望这个小例子能帮助你理解发生了什么。
  • 我在 OP 中没有看到任何 fg 锁定。这是一个不正确的答案,或者充其量是令人困惑的答案。
  • thread1 如何“阻塞”fg?为什么thread2不能访问fg?我在这里可以看到没有锁定。
猜你喜欢
  • 2014-01-05
  • 2018-11-03
  • 1970-01-01
  • 2015-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多