Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get a Java Thread to notify itself?

I have a Thread that handles operations in a queue. Basically, loop forever. If there are operations in the queue, dequeue an operation and execute it. If there are no operations, wait until you're told there are.

In pseudo code (ignore critical sections for now):

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
    }
}

Basically a Controller class initializes this OperationHandler and start()s it. Whenever some requests arrives, the controller calls operationRequired on the thread so that the operations is handled asynchronously in the infinite while loop. Is there any way to achieve this?

I've tried with this.wait() and this.notify() but I get either deadlock or IllegalMonitorStateException depending on different synchronized blocks.

like image 860
Sotirios Delimanolis Avatar asked Apr 18 '26 06:04

Sotirios Delimanolis


1 Answers

How to get a Java Thread to notify itself?

You can't get a Thread to notify itself since it is blocked in wait(). You can have another thread notify the thread by synchronizing on the same object that the thread is locking on and calling notify(). See the below code for a sample.

That said, I'd recommend using a BlockingQueue to share data in this respect. It takes care of all of the locking and signaling. All the thread does is call take() and it will wait for the next operation to be added to the queue with a put().

Lastly, it's always recommended to implement Runnable instead of extending Thread. Once you turn your thread into a runnable you can use the ExecutorService classes as @Peter mentions in his answer. With an ExecutorService your code would look like:

 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());
 ...

But if you still want to tweak your code to get it to work:

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

  // called by another thread
  public void operationRequired() {
     synchronized (lockObject) {
        ...
        lockObject.notify();
     }
  }
like image 51
Gray Avatar answered Apr 20 '26 12:04

Gray



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!