Как перенести задачу с помощью службы ScheduledExecutorService?
Я видел это в java-документах: ScheduledAtFixedRate, говорится
Если какое-либо выполнение задачи встречает исключение, последующее казни подавлены
Я не хочу, чтобы это произошло в моем приложении. Даже если я вижу исключение, я всегда хотел бы, чтобы последующие казни выполнялись и продолжались. Как я могу получить это поведение от ScheduledExecutorService
.
Ответы
Ответ 1
Окружать метод Callable.call или метод Runnable.run с помощью try/catch...
например:
public void run()
{
try
{
// ... code
}
catch(final IOException ex)
{
// handle it
}
catch(final RuntimeException ex)
{
// handle it
}
catch(final Exception ex)
{
// handle it
}
catch(final Error ex)
{
// handle it
}
catch(final Throwable ex)
{
// handle it
}
}
Обратите внимание, что улавливание чего-либо другого, кроме того, что говорит вам компилятор (исключение IOException в моем примере), не очень хорошая идея, но есть несколько раз, и это звучит как один из них, и это может сработать, если вы правильно отрегулируйте его.
Помните, что такие вещи, как Ошибка, очень плохие - у VM закончилась нехватка памяти и т.д., поэтому будьте осторожны с тем, как вы их обрабатываете (именно поэтому я отделил их от своих собственных обработчиков, а не просто делает catch (final Throwable ex ) и ничего больше).
Ответ 2
Попробуйте VerboseRunnable
класс из jcabi-log, который делает обертку, предложенную TofuBeer:
import com.jcabi.log.VerboseRunnable;
Runnable runnable = new VerboseRunnable(
Runnable() {
public void run() {
// do business logic, may Exception occurs
}
},
true // it means that all exceptions will be swallowed and logged
);
Теперь, когда кто-либо звонит runnable.run()
, не генерируются исключения. Вместо этого они проглатываются и регистрируются (для SLF4J).
Ответ 3
У меня была та же проблема. Я также попытался попробовать блок в методе run(), но он не работает.
Итак, я сделал что-то до сих пор:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
public class Test2 {
static final ExecutorService pool = Executors.newFixedThreadPool(3);
static final R1 r1 = new R1();
static final R2 r2 = new R2();
static final BlockingQueue deadRunnablesQueue = new LinkedBlockingQueue<IdentifiableRunnable>();
static final Runnable supervisor = new Supervisor(pool, deadRunnablesQueue);
public static void main(String[] args) {
pool.submit(r1);
pool.submit(r2);
new Thread(supervisor).start();
}
static void reSubmit(IdentifiableRunnable r) {
System.out.println("given to an error, runnable [" + r.getId()
+ "] will be resubmited");
deadRunnablesQueue.add(r);
}
static interface IdentifiableRunnable extends Runnable {
String getId();
}
static class Supervisor implements Runnable {
private final ExecutorService pool;
private final BlockingQueue<IdentifiableRunnable> deadRunnablesQueue;
Supervisor(final ExecutorService pool,
final BlockingQueue<IdentifiableRunnable> deadRunnablesQueue) {
this.pool = pool;
this.deadRunnablesQueue = deadRunnablesQueue;
}
@Override
public void run() {
while (true) {
IdentifiableRunnable r = null;
System.out.println("");
System.out
.println("Supervisor will wait for a new runnable in order to resubmit it...");
try {
System.out.println();
r = deadRunnablesQueue.take();
} catch (InterruptedException e) {
}
if (r != null) {
System.out.println("Supervisor got runnable [" + r.getId()
+ "] to resubmit ");
pool.submit(r);
}
}
}
}
static class R1 implements IdentifiableRunnable {
private final String id = "R1";
private long l;
@Override
public void run() {
while (true) {
System.out.println("R1 " + (l++));
try {
Thread.currentThread().sleep(5000);
} catch (InterruptedException e) {
System.err.println("R1 InterruptedException:");
}
}
}
public String getId() {
return id;
}
}
static class R2 implements IdentifiableRunnable {
private final String id = "R2";
private long l;
@Override
public void run() {
try {
while (true) {
System.out.println("R2 " + (l++));
try {
Thread.currentThread().sleep(5000);
} catch (InterruptedException e) {
System.err.println("R2 InterruptedException:");
}
if (l == 3) {
throw new RuntimeException(
"R2 error.. Should I continue to process ? ");
}
}
} catch (final Throwable t) {
t.printStackTrace();
Test2.reSubmit(this);
}
}
public String getId() {
return id;
}
}
}
Вы можете попытаться прокомментировать Test2.reSubmit(this), чтобы увидеть, что без него R2 перестанет работать.
Ответ 4
Если все, что вам нужно, это последующие исполнения, которые должны произойти и продолжаться даже после исключений, этот код должен работать.
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
Runnable task = new Runnable() {
@Override
public void run() {
try{
System.out.println(new Date() + " printing");
if(true)
throw new RuntimeException();
} catch (Exception exc) {
System.out.println(" WARN...task will continiue"+
"running even after an Exception has araised");
}
}
};
executor.scheduleAtFixedRate(task, 0, 3, TimeUnit.SECONDS);
Если произошел a Throwable
, отличный от Exception
, вам может не потребоваться выполнение последующих исполнений.
Вот вывод
Пт ноя 23 12:09:38 JST 2012 печать
_WARN... задача будет Continuuerunning даже после того, как Exception поднялся
Пятница 23 ноября 12:09:41 JST 2012 печать
_WARN... задача будет продолжаться даже после того, как Исключение поднялось
Пт ноя 23 12:09:44 JST 2012 печать
_WARN... задача будет продолжаться даже после Исключение поднялось
Пт ноя 23 12:09:47 JST 2012 печать
Задача _WARN... будет продолжена даже после того, как Исключение создало