2

我有一个处理队列中操作的线程。基本上,永远循环。如果队列中有操作,则将操作出列并执行。如果没有操作,请等到您被告知有操作。

在伪代码中(暂时忽略关键部分):

public class OperationHandler extends Thread {
    private Deque<Operation> queue = new LinkedList<>();
    public void run() {
        while (true) {
            if (queue isn't empty) {
                 dequeue the operation and execute it
            }
            else {
                wait;
            }
        }
    }

    public void operationRequired() {
        add operation to queue
        notify yourself / return to infinite while loop
    }
}

基本上,一个 Controller 类初始化 thisOperationHandlerstart()s 它。每当一些请求到达时,控制器就会调用operationRequired线程,以便在无限while循环中异步处理操作。有什么办法可以做到这一点?

我试过了this.wait()this.notify()但我要么死锁,要么IllegalMonitorStateException取决于不同的同步块。

4

4 回答 4

9

如何让 Java 线程通知自己?

您无法让 Thread 通知自己,因为它被阻止在wait(). 您可以让另一个线程通过在线程锁定并调用的同一对象上同步来通知该线程notify()。请参阅下面的代码以获取示例。

也就是说,我建议BlockingQueue在这方面使用 a 来共享数据。它负责所有的锁定和信令。线程所做的只是调用take(),它将等待下一个操作被添加到队列中put()

最后,始终建议实施Runnable而不是扩展Thread. 一旦你把你的线程变成一个可运行的,你就可以使用ExecutorService@Peter在他的回答中提到的类。使用ExecutorService您的代码将如下所示:

 public class OperationHandler implements Runnable {
     public void run() {
        // no looping or dequeuing needed
        // just execute the job
     }
 }

 // create a thread pool with a single thread worker
 ExecutorService threadPool = Executors.newSingleThreadExecutor();
 // or create a thread pool with 10 workers
 // ExecutorService threadPool = Executors.newFixedThreadPool(10);
 // or you can create an open-ended thread pool
 // ExecutorService threadPool = Executors.newCachedThreadPool();
 ...
 // do this once or many times
 threadPool.submit(new OperationHandler());
 ...

但是,如果您仍想调整代码以使其正常工作:

  private final Object lockObject = new Object();
  public void run() {
     synchronized (lockObject) {
        ...
        lockObject.wait();
     }
  }

  // called by another thread
  public void operationRequired() {
     synchronized (lockObject) {
        ...
        lockObject.notify();
     }
  }
于 2013-01-24T21:00:44.540 回答
2

如果在没有线程等待()时通知(),它将被忽略。即,线程通知自己是没有意义的,因为它不能同时等待和通知。

如果你有一个队列和线程,你可能应该使用一个包装两者的 ExecutorService。顺便说一句,它使用 BlockingQueue

于 2013-01-24T21:01:20.187 回答
1

如果您的operationRequired方法正在等待,则不能使用同一线程调用它。尽管它在同一个线程类中,但很可能会与另一个线程一起执行。

所以使用正常同步:首先进入监视器,synchronized然后等待或通知。另一种选择是使用队列形式java.util.concurrent.*。他们在内部支持这些东西。

于 2013-01-24T21:02:11.277 回答
0

美国 aBlockingQueue及其take()操作。它已经嵌入了等待和通知。

于 2013-01-25T10:07:11.170 回答