Java 与多线程服务器的繁忙循环相比,互斥体导致丢失输入?

Java mutex causing missing input compared to busy loop for multithreaded server?

我正在编写一个 Java 程序,它与我的 Linux 服务器上的 C 程序接口(这是一个 client/server 聊天程序)。现在,我正在为输入实施阻塞功能,直到用户在将输入发送到服务器之前按下“Enter”。为此,我有两个选择:忙循环和互斥锁。互斥锁显然是最好的选择,但我 运行 遇到一个问题,有时输入根本不会发送到服务器。不过,在繁忙的循环中,我只是取消了一个标志,它工作正常。

忙循环:

while(!this.inputField.isReady()){}
// send data in inputField to server
this.inputField.setReady(false);

所以,我需要在文本字段中(在键盘监听器中)做的是:

...
public void keyPressed(KeyEvent e) {
  if (e.getKeyCode() == KeyEvent.VK_ENTER) {
    ready = true;
    setText("");
  }
}
...

所以,是的,这行得通。我的互斥锁解决方案就没那么幸运了:

while (!this.inputField.isReady()) {
  synchronized(this.inputField.mutex) {
    try {
      this.inputField.mutex.wait();
    } ... //redacted for simplicity
  }
}

通知者:

...
ready = true; 
// This is in the TextField class.
synchronized(this.mutex) {
  this.mutex.notify();
}
setText("");
...

也许我误解了 Java 同步功能的一个基本部分(这在 C 语言中更容易...)。互斥量只是一个标准对象,遵循在线示例。请注意,我确实尝试了 notifyAll,但没有用。任何帮助将不胜感激。

你的互斥体什么都不做。它没有保护任何东西。

如果共享状态是就绪标志,那么互斥量必须保护就绪标志。所以:

synchronized(this.inputField.mutex) {
   while (!this.inputField.isReady()) {
    try {
      this.inputField.mutex.wait();
    } ... //redacted for simplicity
  }
}

请注意,如果不持有互斥量就无法调用 isReady,因为互斥量会保护就绪前后的同步。同样:

...
// This is in the TextField class.
synchronized(this.mutex) {
  ready = true; 
  this.mutex.notify();
}
setText("");
...

互斥体必须保护共享状态。如果共享状态是就绪标志,则没有线程可以在不持有互斥锁的情况下访问就绪标志。

您没有显示 isReady 的实现,但如果它本身获取了互斥体,那是不够的。您无法获取互斥锁、检查就绪、释放互斥锁,然后调用 wait。如果就绪标志在 isReady returns 之后但在您输入 wait.

之前更改状态,则会产生竞争条件