I have two APIs: one starts the thread, and another stops the thread. I'm successfully able to start a thread by calling /start API, but I'm unable to stop already running thread by calling /stop API. Seems like Executor#stop() does nothing.
My RestController:
#Autowired
private Executor executor;
#RequestMapping(path = "/start", method = GET)
public ResponseEntity<HttpStatus> startLongTask() {
executor.start();
return ResponseEntity.ok(HttpStatus.OK);
}
#RequestMapping(path = "/stop", method = GET)
public ResponseEntity<HttpStatus> stopLongTask() {
executor.stop();
return ResponseEntity.ok(HttpStatus.OK);
}
My Executor:
#Component
public class Executor {
#Value("${threads.number}")
private int threadsNumber;
private ExecutorService executorService;
#Autowired
private OtherService otherService;
#PostConstruct
private void init() {
executorService = Executors.newFixedThreadPool(threadsNumber);
executorService = Executors.newScheduledThreadPool(threadsNumber);
}
/**
* Start.
*/
public void start() {
executorService.submit(() -> otherService.methodImExecuting());
}
/**
* Stop.
*/
#PreDestroy
publicvoid stop() {
executorService.shutdownNow();
try {
if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
}
}
}
Here's the methodImExecuting:
#Component
public class OtherService {
public void methodImExecuting() {
List<SomeObject> dataList = repository.getDataThatNeedsToBeFilled();
for (SomeObject someObject : dataList) {
gatewayService.sendDataToOtherResourceViaHttp(someObject);
}
}
}
Short answer: You can not stop a running thread which does not cooperate. There's a deprecated destroy() method for threads, but this will lead to a "bad" state of your VM.
The only possibility to end the Thread clean is to interrupt it. But to check for interruption is the task of the thread itself.
So your methodImExcecuting sould look like:
void methodImExecuting() throws InterruptedException {
// it depends on your implementation, I assume here that you iterate
// over a collection for example
int loopCount = 0;
for (Foo foo : foos) {
++loopCount;
if (loopCount % 100 == 0) {
if (Thread.interrupted())
throw new InterruptedException();
}
...
}
It depends on your implementation how often you have to look if your thread was interrupted. But it's a fact that the call of executorService.shutdownNow(); will only set the interrupted flag of all threads currently running in the executorService. To really interrupt the thread, the thread must itself check if the interrupted flag is set and then throw an InterruptedException
Your running threads have to react to the interrupt signal
Thread.currentThread().isInterrupted()
Otherwise the sending of the interrupt signal has no effect.
Here you can find a good explanation:
Difference between shutdown and shutdownNow of Executor Service
Related
I am using spring boot and have one async method. To execute async I have below configuration, questions is what if all those 5 thread hangs for some reason , essentially it will lock the application and none of new task will be executed (it will just keep accepting). How we can set timeout for those working thread , lets say 120 seconds, so after that it timesout and execute new task. (Yes I am using fixed thread pool with unbounded queue to keep accepting tasks)
#EnableAsync
#Configuration
public class AsyncConfiguration implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(5);
taskExecutor.setMaxPoolSize(5);
taskExecutor.initialize();
return taskExecutor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
You can create another executor like:
static class TimeOutExecutorService extends CompletableExecutors.DelegatingCompletableExecutorService {
private final Duration timeout;
private final ScheduledExecutorService schedulerExecutor;
TimeOutExecutorService(ExecutorService delegate, Duration timeout) {
super(delegate);
this.timeout = timeout;
schedulerExecutor = Executors.newScheduledThreadPool(1);
}
#Override public <T> CompletableFuture<T> submit(Callable<T> task) {
CompletableFuture<T> cf = new CompletableFuture<>();
Future<?> future = delegate.submit(() -> {
try {
cf.complete(task.call());
} catch (CancellationException e) {
cf.cancel(true);
} catch (Throwable ex) {
cf.completeExceptionally(ex);
}
});
schedulerExecutor.schedule(() -> {
if (!cf.isDone()) {
cf.completeExceptionally(new TimeoutException("Timeout after " + timeout));
future.cancel(true);
}
}, timeout.toMillis(), TimeUnit.MILLISECONDS);
return cf;
}
}
Then, create a new bean named timed
#Bean(name = "timed")
public Executor timeoutExecutor() {
ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("timed-%d").build();
return TimedCompletables.timed(Executors.newFixedThreadPool(10, threadFactory), Duration.ofSeconds(2));
}
And, try to use this Executor to execute your async tasks.
Or, try to change your code from FixSizeThreadPool to build a own thread pool executor.
You can not submit some task with timeout. What you can do is when you submit your task your get a Future object. You can keep this reference in some Map and pole and see if the task keeps running past your timeout. If so you can use the method cancel() of class Future.
Alternatively, your own task when it starts running places its own current thread into some Map visible to your main (submitting) thread. Also if you see that your task didn't finish in time (again poling) you can try and interrupt your thread. In either case your submitted task should be able to react to interrupt() method of Thread class. I actually implemented this alternative way. If you go this way, test a LOT... :)
I think Future.get(timeout, unit) method can manage async timeout.
Following example can work on my local.
#SpringBootApplication
#EnableScheduling
#EnableAsync
public class AsyncTimeoutExampleAppliation {
private final MyService myService;
public AsyncTimeoutExampleAppliation(MyService myService) {
this.myService = myService;
}
public static void main(String[] args) {
SpringApplication.run(AsyncTimeoutExampleAppliation.class, args);
}
#PostConstruct
void postConstract(){
asyncCall();
}
public void asyncCall(){
try {
String result = myService.doSomething()
.get(10, TimeUnit.SECONDS);
System.out.println(result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
#Service
public static class MyService {
#Async
public Future<String> doSomething() throws InterruptedException {
TimeUnit.SECONDS.sleep(60);
return CompletableFuture.completedFuture("Finished");
}
}
}
We can get TimeoutException 10 seconds after application starts.
I have a long running Runnable object and I wanted to provide a more graceful interrupt mechanism than having to call interrupt on the thread the object is running on.
The before code:
public class MyRunnable implements Runnable {
public void run() {
while(!Thread.currentThread().isInterrupted()) {
//do stuff
}
}
}
public class MyClass {
public static void main(String[] args) {
Runnable myRunnable = new MyRunnable();
Thread t = new Thread(myRunnable, "myRunnableThread");
t.start();
//do stuff
t.interrupt();
//do stuff
}
}
And the new code:
public class MyRunnable implements Runnable {
private Thread myThread = null;
public void run() {
myThread = Thread.currentThread();
while(!myThread.isInterrupted()) {
//do stuff
}
}
public void shutdown() {
if (myThread != null) {
myThread.interrupt();
//do other shutdown stuff
}
}
}
public class MyClass {
public static void main(String[] args) {
Runnable myRunnable = new MyRunnable();
Thread t = new Thread(myRunnable, "myRunnableThread");
t.start();
//do stuff
myRunnable.shutdown();
//do stuff
}
}
My question is, are there possible side effects or unknowns that holding a reference to your own thread, and providing limited access to that thread through public methods (as above) could cause? This is assuming that no-one ever calls the run() method directly, that it is always started from a new thread.
And I'm aware that I could use a volatile or atomic Boolean in the run() and shutdown() methods for communicating intent to shutdown, I'm more interested in learning than a solution. But solutions are still welcome!
For me your first approach is much better as less error prone and more "standard". But actually what you try to implement already exists (which proves that it makes sense and that it is not a bad practice but it is not easy to make it properly), it is called FutureTask, instead of shutdown you have cancel(boolean mayInterruptIfRunning) with true as value of mayInterruptIfRunning if you want to interrupt the thread running the task, I quote the javadoc:
Attempts to cancel execution of this task. This attempt will fail if
the task has already completed, has already been cancelled, or could
not be cancelled for some other reason. If successful, and this task
has not started when cancel is called, this task should never run. If
the task has already started, then the mayInterruptIfRunning
parameter determines whether the thread executing this task should be
interrupted in an attempt to stop the task.
For example:
// Task that will only sleep for 1 sec and print a message on interrupted
FutureTask<Void> myRunnable = new FutureTask<>(
new Callable<Void>() {
#Override
public Void call() throws Exception {
try {
System.out.println("Sleep");
Thread.sleep(1_000L);
} catch (InterruptedException e) {
System.out.println("Interrupted !!!");
throw e;
}
return null;
}
}
);
new Thread(myRunnable, "myRunnableThread").start();
// Wait long enough to make sure that myRunnableThread is sleeping
Thread.sleep(500L);
// Cancel the task and interrupt myRunnableThread
myRunnable.cancel(true);
Output:
Sleep
Interrupted !!!
It already has a reference:
Thread.currentThread()
From the javadoc:
Returns a reference to the currently executing thread object.
I need a solution to properly stop the thread in Java.
I have IndexProcessorclass which implements the Runnable interface:
public class IndexProcessor implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);
#Override
public void run() {
boolean run = true;
while (run) {
try {
LOGGER.debug("Sleeping...");
Thread.sleep((long) 15000);
LOGGER.debug("Processing");
} catch (InterruptedException e) {
LOGGER.error("Exception", e);
run = false;
}
}
}
}
And I have ServletContextListener class which starts and stops the thread:
public class SearchEngineContextListener implements ServletContextListener {
private static final Logger LOGGER = LoggerFactory.getLogger(SearchEngineContextListener.class);
private Thread thread = null;
#Override
public void contextInitialized(ServletContextEvent event) {
thread = new Thread(new IndexProcessor());
LOGGER.debug("Starting thread: " + thread);
thread.start();
LOGGER.debug("Background process successfully started.");
}
#Override
public void contextDestroyed(ServletContextEvent event) {
LOGGER.debug("Stopping thread: " + thread);
if (thread != null) {
thread.interrupt();
LOGGER.debug("Thread successfully stopped.");
}
}
}
But when I shutdown tomcat, I get the exception in my IndexProcessor class:
2012-06-09 17:04:50,671 [Thread-3] ERROR IndexProcessor Exception
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at lt.ccl.searchengine.processor.IndexProcessor.run(IndexProcessor.java:22)
at java.lang.Thread.run(Unknown Source)
I am using JDK 1.6. So the question is:
How can I stop the thread and not throw any exceptions?
P.S. I do not want to use .stop(); method because it is deprecated.
Using Thread.interrupt() is a perfectly acceptable way of doing this. In fact, it's probably preferrable to a flag as suggested above. The reason being that if you're in an interruptable blocking call (like Thread.sleep or using java.nio Channel operations), you'll actually be able to break out of those right away.
If you use a flag, you have to wait for the blocking operation to finish and then you can check your flag. In some cases you have to do this anyway, such as using standard InputStream/OutputStream which are not interruptable.
In that case, when a thread is interrupted, it will not interrupt the IO, however, you can easily do this routinely in your code (and you should do this at strategic points where you can safely stop and cleanup)
if (Thread.currentThread().isInterrupted()) {
// cleanup and stop execution
// for example a break in a loop
}
Like I said, the main advantage to Thread.interrupt() is that you can immediately break out of interruptable calls, which you can't do with the flag approach.
In the IndexProcessor class you need a way of setting a flag which informs the thread that it will need to terminate, similar to the variable run that you have used just in the class scope.
When you wish to stop the thread, you set this flag and call join() on the thread and wait for it to finish.
Make sure that the flag is thread safe by using a volatile variable or by using getter and setter methods which are synchronised with the variable being used as the flag.
public class IndexProcessor implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);
private volatile boolean running = true;
public void terminate() {
running = false;
}
#Override
public void run() {
while (running) {
try {
LOGGER.debug("Sleeping...");
Thread.sleep((long) 15000);
LOGGER.debug("Processing");
} catch (InterruptedException e) {
LOGGER.error("Exception", e);
running = false;
}
}
}
}
Then in SearchEngineContextListener:
public class SearchEngineContextListener implements ServletContextListener {
private static final Logger LOGGER = LoggerFactory.getLogger(SearchEngineContextListener.class);
private Thread thread = null;
private IndexProcessor runnable = null;
#Override
public void contextInitialized(ServletContextEvent event) {
runnable = new IndexProcessor();
thread = new Thread(runnable);
LOGGER.debug("Starting thread: " + thread);
thread.start();
LOGGER.debug("Background process successfully started.");
}
#Override
public void contextDestroyed(ServletContextEvent event) {
LOGGER.debug("Stopping thread: " + thread);
if (thread != null) {
runnable.terminate();
thread.join();
LOGGER.debug("Thread successfully stopped.");
}
}
}
Simple answer:
You can stop a thread INTERNALLY in one of two common ways:
The run method hits a return subroutine.
Run method finishes, and returns implicitly.
You can also stop threads EXTERNALLY:
Call system.exit (this kills your entire process)
Call the thread object's interrupt() method *
See if the thread has an implemented method that sounds like it would work (like kill() or stop())
*: The expectation is that this is supposed to stop a thread. However, what the thread actually does when this happens is entirely up to what the developer wrote when they created the thread implementation.
A common pattern you see with run method implementations is a while(boolean){}, where the boolean is typically something named isRunning, it's a member variable of its thread class, it's volatile, and typically accessible by other threads by a setter method of sorts, e.g. kill() { isRunnable=false; }. These subroutines are nice because they allow the thread to release any resources it holds before terminating.
You should always end threads by checking a flag in the run() loop (if any).
Your thread should look like this:
public class IndexProcessor implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);
private volatile boolean execute;
#Override
public void run() {
this.execute = true;
while (this.execute) {
try {
LOGGER.debug("Sleeping...");
Thread.sleep((long) 15000);
LOGGER.debug("Processing");
} catch (InterruptedException e) {
LOGGER.error("Exception", e);
this.execute = false;
}
}
}
public void stopExecuting() {
this.execute = false;
}
}
Then you can end the thread by calling thread.stopExecuting(). That way the thread is ended clean, but this takes up to 15 seconds (due to your sleep).
You can still call thread.interrupt() if it's really urgent - but the prefered way should always be checking the flag.
To avoid waiting for 15 seconds, you can split up the sleep like this:
...
try {
LOGGER.debug("Sleeping...");
for (int i = 0; (i < 150) && this.execute; i++) {
Thread.sleep((long) 100);
}
LOGGER.debug("Processing");
} catch (InterruptedException e) {
...
Typically, a thread is terminated when it's interrupted. So, why not use the native boolean? Try isInterrupted():
Thread t = new Thread(new Runnable(){
#Override
public void run() {
while(!Thread.currentThread().isInterrupted()){
// do stuff
}
}});
t.start();
// Sleep a second, and then interrupt
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
t.interrupt();
ref- How can I kill a thread? without using stop();
For synchronizing threads I prefer using CountDownLatch which helps threads to wait until the process being performed complete. In this case, the worker class is set up with a CountDownLatch instance with a given count. A call to await method will block until the current count reaches zero due to invocations of the countDown method or the timeout set is reached. This approach allows interrupting a thread instantly without having to wait for the specified waiting time to elapse:
public class IndexProcessor implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);
private final CountDownLatch countdownlatch;
public IndexProcessor(CountDownLatch countdownlatch) {
this.countdownlatch = countdownlatch;
}
public void run() {
try {
while (!countdownlatch.await(15000, TimeUnit.MILLISECONDS)) {
LOGGER.debug("Processing...");
}
} catch (InterruptedException e) {
LOGGER.error("Exception", e);
run = false;
}
}
}
When you want to finish execution of the other thread, execute countDown on the CountDownLatch and join the thread to the main thread:
public class SearchEngineContextListener implements ServletContextListener {
private static final Logger LOGGER = LoggerFactory.getLogger(SearchEngineContextListener.class);
private Thread thread = null;
private IndexProcessor runnable = null;
private CountDownLatch countdownLatch = null;
#Override
public void contextInitialized(ServletContextEvent event) {
countdownLatch = new CountDownLatch(1);
Thread thread = new Thread(new IndexProcessor(countdownLatch));
LOGGER.debug("Starting thread: " + thread);
thread.start();
LOGGER.debug("Background process successfully started.");
}
#Override
public void contextDestroyed(ServletContextEvent event) {
LOGGER.debug("Stopping thread: " + thread);
if (countdownLatch != null)
{
countdownLatch.countDown();
}
if (thread != null) {
try {
thread.join();
} catch (InterruptedException e) {
LOGGER.error("Exception", e);
}
LOGGER.debug("Thread successfully stopped.");
}
}
}
Some supplementary info.
Both flag and interrupt are suggested in the Java doc.
https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html
private volatile Thread blinker;
public void stop() {
blinker = null;
}
public void run() {
Thread thisThread = Thread.currentThread();
while (blinker == thisThread) {
try {
Thread.sleep(interval);
} catch (InterruptedException e){
}
repaint();
}
}
For a thread that waits for long periods (e.g., for input), use Thread.interrupt
public void stop() {
Thread moribund = waiter;
waiter = null;
moribund.interrupt();
}
I didn't get the interrupt to work in Android, so I used this method, works perfectly:
boolean shouldCheckUpdates = true;
private void startupCheckForUpdatesEveryFewSeconds() {
threadCheckChat = new Thread(new CheckUpdates());
threadCheckChat.start();
}
private class CheckUpdates implements Runnable{
public void run() {
while (shouldCheckUpdates){
System.out.println("Do your thing here");
}
}
}
public void stop(){
shouldCheckUpdates = false;
}
Brian Goetz in his book suggests to use Thread.currentThread().isInterrupted() flag and interrupt() method for cancellation.
Blocking library methods like sleep() and wait() try to detect when a thread has been interrupted and return early. They respond to interruption by clearing the interrupted status and throwing InterruptedException, indicating that the blocking operation completed early due to interruption.
The JVM makes no guarantees on how quickly a blocking method will detect interruption, but in practice this happens reasonably quickly.
class PrimeProducer extends Thread {
private final BlockingQueue<BigInteger> queue;
PrimeProducer(BlockingQueue<BigInteger> queue) {
this.queue = queue;
}
public void run() {
try {
BigInteger p = BigInteger.ONE;
while (!Thread.currentThread().isInterrupted()) {
queue.put(p = p.nextProbablePrime()); // blocking operation
}
} catch (InterruptedException consumed) {
// allow thread to exit
}
// any code here will still be executed
}
public void cancel() {
interrupt();
}
}
If you put any code after catch block, it will still be executed as we swallow InterruptedException to exit from run() gracefully.
Just a couple words on how interrupt() works.
If interrupt is called on non-blocked thread, interrupt() will not cause InterruptedException inside run() but will just change flag isInterrupted to true and thread will continue its work until it reaches Thread.currentThread().isInterrupted() check and exit from run().
If interrupt is called on blocked thread (sleep() or wait()was called, in our case it's put() that might block a thread) then isInterrupted will be set to false and InterruptedException will be thrown inside put().
I have a BlockingQueue that processes work events on a single background thread. Various threads call add to add some work to the queue and a single background thread calls take to get the work and process it one a time. Eventually it may be time to stop the processing of work and I want to make sure that the callers who requested work either get their results or get null indicating their work was not done because the BlockingQueue is shutting down.
How do I cleanly stop accepting new work, the best I can think of is to set BlockingQueue field to null and then catch NullPointerException when add is called. Before setting the field to null I will keep a local copy of the pointer so I can drain it after it has stopped accepting work. I think that will work, but it seems a bit hacky, is there a proper way to do this?
Here is what the code looks like now:
ArrayBlockingQueue<Command> commandQueue =
new ArrayBlockingQueue<Command>(100, true);
public boolean addToQueue(Command command) {
try {
return commandQueue.add(command);
} catch (IllegalStateException e) {
return false;
}
}
#Override
public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {
Command command = commandQueue.take();
// ... work happens here
// result is sent back to caller
command.provideResponseData(response);
}
} catch (InterruptedException e) {
// Break out of the loop and stop
}
// TODO: stop accepting any new work, drain the queue of existing work
// and provide null responses
}
Rather than work with BlockingQueue and a worker thread, consider using a single-thread ThreadPoolExecutor. Something like this:
private class CommandRunner implements Runnable {
public CommandRunner(Command command) {
this.command = command;
}
public void run() {
// ... work happens here
// result is sent back to caller
command.provideResponseData(response);
}
}
private ExecutorService commandExecutor = Executors.newSingleThreadExecutor();
public boolean addToQueue(Command command) {
commandExecutor.submit(new CommandRunner(command));
}
And then your shutdown methods can delegate to the executor.
As mentioned before, use an ExecutorService or ThreadPool, but submit Callables instead of mere Runnables. Have your worker threads observe some stop signal (maybe an AtomicBoolean visible to all of them). If the flag has been set, make the Callables return a special value to indicate that nothing was done. Callers must retain the Future returned by submit to get the Callable's result.
Maybe I should elaborate some more. If you are currently using Runnables, maybe wrap them in Callables and, in call, check the stop flag. If you set the stop flag before you call ExecutorService.shutdown, it will complete the current job normally, but effectively cancel all remaining jobs, therefore draining the remaining queue fast. If you do not shut down, you can even reuse the ExecutorService after resetting the stop flag.
static enum EResult {
Cancelled, Completed
}
static abstract class MyCallable implements Callable<EResult> {
Runnable runner;
public MyCallable( Runnable runner) {
super();
this.runner = runner;
}
}
static AtomicBoolean cancelled = new AtomicBoolean( false);
static void main( String[] argv) {
Runnable runnable = new Runnable() {
#Override
public void run() {
System.out.println( "Done");
}
};
Callable<EResult> callable = new MyCallable( runnable) {
#Override
public EResult call() throws Exception {
if ( cancelled.get()) {
return EResult.Cancelled;
}
runner.run();
return EResult.Completed;
}
};
ExecutorService executorService = Executors.newFixedThreadPool( 1);
// while submitting jobs, change cancelled at some point
Future<EResult> future = executorService.submit( callable);
try {
EResult completeOrNot = future.get();
System.out.println( "result: " + completeOrNot);
} catch ( InterruptedException e) {
e.printStackTrace();
} catch ( ExecutionException e) {
e.printStackTrace();
}
}
I've got a inner class in my class doing some asynchronous processing and setting value on parent class. Ex :
class Myclass{
String test;
public getTestValueFromMyClass(){
//this starts asynchronous processing on my inner class
}
//inner class
class InnerClass extends TimerTask{
//doing something asynchronously, when this process is done
test = "somevalue";
}
}
Now here is the problem from Runner class :
class Runner{
public static void main(String[] args){
Myclass instance = new Myclass();
//This is always null because runner class doesn't wait for Inner class to
//complete asynchronous processing and to set test value
System.out.println(instance.getTestValueFromMyClass());
}
}
How do I get around this?
Others have suggested similar ideas but I'd use a single thread pool with a Callable.
Your class that is doing the asynchronous processing should implement Callable which will return the computed value. In this example it returns a String but it could also return your own object with more information.
public class MyClass implements Callable<String> {
public String call() {
//doing something asynchronously, when this process is done
return "somevalue";
}
}
Your Runner class would then create a thread pool, fire off the asynchronous task in the background, and then later wait for it to finish. When you submit a Callable job to the thread-pool, you get a Future class back which can be used to wait for the asynchronous job to finish and to get its return value.
public class Runner{
public static void main(String[] args) {
// you can use newFixedThreadPool(...) if you need to submit multiple
ExecutorService threadPool = Executors.newSingleThreadExecutor();
// you could store this future in a collection if you have multiple
Future<String> future = threadPool.submit(new MyClass());
// after submitting the final job, we _must_ shutdown the pool
threadPool.shutdown();
// do other stuff in the "foreground" while MyClass runs in the background
// wait for the background task to complete and gets its return value
// this can throw an exception if the call() method threw
String value = future.get();
System.out.println(value);
}
}
Evidently, you have to make getTestValueFromMyClass to wait for InnerClass execution. This can be done with some synchronization facility (Semaphore, CountdownLatch, BlockingQueue...). But most straightforward is to use java.util.concurrent.ScheduledThreadPoolExecutor instead of java.util.Timer. Its method schedule(Callable<V> callable, long delay, TimeUnit unit) returns Future, and Future.get() waits for and returns the computed value.
One very simple mechanism is to use a BlockingQueue to communicate between your threads. Here I am creating the queue in the thread class but it could just as easily be created in the caller and passed to the thread.
public class Runner {
static class MyClass implements Runnable {
// Thread will post to this queue when it completes.
BlockingQueue q = new ArrayBlockingQueue(1);
// Call to wait for the post.
public void waitForFinish() throws InterruptedException {
// Just take! This will wait until something gets posted.
q.take();
}
#Override
public void run() {
try {
// Just wait ten seconds.
Thread.sleep(10000);
} catch (InterruptedException ex) {
// Just exit when interrupted.
} finally {
try {
// Signal finished.
q.put("Done");
} catch (InterruptedException ex) {
// Just exit when interrupted.
}
}
}
}
public static void main(String[] args) throws InterruptedException {
// Make my instance.
MyClass instance = new MyClass();
// Fire it off.
new Thread(instance).start();
// Wait for it to finish.
instance.waitForFinish();
// All done.
System.out.println("Finished");
}
}
You could use a handler and post a message when processing is done!
class Myclass{
// pre initialize thread pool
private static ExecutorService executor = Executors.newFixedThreadPool( 5 );
private String test;
public String getTestValueFromMyClass() throws Exception {
// start asynchronous calculations
Future<String> resultHandler =
executor.submit( new Callable<String>() {
#Override
public String call() throws Exception {
return "Asynchronously calculated result";
}
} );
// do something in current thread
// ...
// wait until asynchronous task ends, get result
// and assign it to instance variable
this.test = resultHandler.get();
return test; // returns string "Asynchronously calculated result"
}
}