Reputation: 187
In java, I have ExecutorService that runs with while true, and Throwable catch clouse. I find out that from time to time the thread goes down. That means the system stop function. So my question is, first of all, how can I catch the "thread killed" event (in order to send me email on such case)? Also, how can this thread goes down?
the code is:
ExecutorService changesTrackerThread = Executors.newSingleThreadExecutor();
changesTrackerThread.submit(queueUpdater());
private Runnable queueUpdater() {
return new Runnable() {
@Override
public void run() {
while (true)
{
try
{
// do some code, then sleep
Thread.sleep(2000L);
} catch (Throwable t)
{
_log.error("something bad happened, but the loop should keep running", t);
}
}
}
};
Upvotes: 3
Views: 164
Reputation: 132410
As others have noted, you could replace your while (true)
and sleep()
loop with a ScheduledExecutorService
. Scheduling a repeating task on such a service will return a ScheduledFuture
which you can use to check the status of this task or to cancel it if you have a need for that. This will enable you to remove the try/catch block from the code.
Start the service like this:
ScheduledExecutorService svc = Executors.newScheduledThreadPool(1);
I would use newScheduledThreadPool()
instead of newSingleThreadScheduledExecutor()
since the former will restart threads if necessary.
Then, schedule the work like this:
void doSomeCode() {
// do some code
}
ScheduledFuture<?> sf = svc.scheduleAtFixedRate(this::doSomeCode, 0L, 2L, TimeUnit.SECONDS);
(Or if you wish you can inline doSomeCode()
as a lambda or an anonymous inner class.)
Now what happens if the task fails with an exception? The ScheduledFuture
object returned allows you to check status in a variety of ways. If you have a thread that you can dedicate to waiting for failures, you can have it call sf.get()
which will throw an ExecutionException
that wraps the exception that caused the task to fail. Otherwise, it blocks indefinitely. ScheduledFuture.get()
is a bit weird in that unlike an ordinary Future.get()
call, it never returns a value; it always throws an exception.
When/if the task fails, the caller of sf.get()
can log the exception and resubmit the task, or whatever. If you don't want to block a thread indefinitely, you can poll for failure using sf.isDone()
or sf.get(0L, TimeUnit.SECONDS)
. Note that both overloads of sf.get()
communicate all of their return information via the type of a thrown exception, which may make them somewhat inconvenient to use.
You could put exception handling within the task itself, catching Throwable
and continuing no matter what, and this will probably work. It does bake the logging/restart/resubmission policy into the task itself, which may be unpleasant. Using ScheduledFuture
lets you separate these policies from the actual work performed by the task.
Upvotes: 1
Reputation: 5133
Well first of all, why are you using a while loop here!?
You should use a scheduled executor:
ExecutorService changesTrackerThread = Executors.newSingleThreadScheduledExecutor()();
changesTrackerThread.scheduleAtFixedRate(new queueUpdater(), 0, 2, TimeUnit.SECONDS);
private Runnable queueUpdater() {
return new Runnable() {
@Override
public void run() {
try
{
// do some code
} catch (Throwable t)
{
_log.error("something bad happened", t);
}
}
};
I do not know why your thread dies, show us the full code.
But this way even if the thread dies the Excecutor will rerun it after the given period(2 seconds in this example.
Upvotes: 3