In Java there are basically 4 primitives to support inter-thread communication:
- Volatile variables.
- Interrupt system.
- Synchronized (methods or blocks).
- wait() + notify() system.
For completeness there is also the Thread.stop()
and Thread.suspend()
methods - but per the documentation they are inherently unsafe and should not be used. Now deprecated for eventual removal. See Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?.
Additionally you should review the java.util.concurrent
package - however my understanding is that the concurrent package is built on top of the 4 primitives listed above, as a result it does not provide any additional capabilities (that you couldn't implement yourself using those primitives).
The first two primitives listed above can be viewed as mechanisms to pause/abort running Threads. The last two are more related to synchronization/correctness and performance optimization (not having idle threads burning CPU).
The simplest case for a volatile variable would be a boolean flag shouldTerminate
it is initialized with a value false. Then your main processing loop in the worker thread would typically have something like:
while(!shouldTerminate) {
// Do something.
}
Hence if you want to signal a worker thread to terminated you can simply set shouldTerminate = true;
and the worker thread will break out of its loop. How many flags you have and which worker Threads use which flags determines the level of control you have over when the workers will be terminated.
The core issue with (only) using volatile variables is that Threads can get blocked in several ways:
- Waiting on a monitor (synchronized block) - possibly during a wait()
- Executing a Thread.sleep()
- Performing IO.
If you only use volatile variables the Thread won't abort until whatever situation is blocking its execution is cleared - once the block is cleared the Thread will then be able to check the variable and if required shut down.
This is where notify() and interrupt() come in:
- notify() allows you to instruct another thread to break out of a wait().
- interrupt() will typically break the other thread out of a sleep() and/or if it is blocked on IO.
Note: notify()
wakes a (single) random thread hence if you have multiple Threads waiting on a single monitor it is generally good practice to use notifyAll()
.
Is there an efficient way to stop the async process?
You can cancel()
on the Future
you get back when scheduling jobs - but if the job is already running this is implemented as an interrupt()
.
Alternatively you can define a variable to signal to the job it should terminate - this is typically a cleaner solution - but it has the drawbacks outlined above.
Edit - Atomic Classes
As @Basil Bourque - points out in the comments the Atomic...
classes are a grey area. I don't consider them primitives themselves, but they do leverage a primitive that I did not mention in my list above (the CAS operations from the VarHandle
class).
The above list of primitives are typically something you might choose to use directly, where as I would recommend using the Atomic...
classes in preference to directly invoking CAS operations.
TBF - since java.util.concurrent
was added I haven't worked with interrupt()
or wait/notify much. I have usually found one of the concurrent classes meets my needs, but I do still use volatile booleans to terminate execution of background threads - this is because I don't know how well third party libraries (typically used in worker threads) would cope with an interrupt. So I would rather accept that there will be a delay, while any IO completes before termination can occur.