Estoy trabajando en un proyecto Java donde necesito tener varias tareas ejecutándose de forma asíncrona. Me hacen creer que el ejecutor es la mejor manera de hacerlo, así que me estoy familiarizando con eso. (¡Sí, se les paga para aprender!) Sin embargo, no está claro para mí cuál es la mejor manera de lograr lo que intento hacer.Mejores prácticas de Java Executor para tareas que deberían ejecutarse Forever
Por el bien del argumento, digamos que tengo dos tareas en ejecución. No se espera que ninguno de los dos finalice y ambos deberían ejecutarse durante la vida de la aplicación. Estoy tratando de escribir una clase contenedora principal tal que:
- Si alguna tarea arroja una excepción, la envoltura la detectará y reiniciará la tarea.
- Si alguna de las tareas se ejecuta hasta su finalización, el contenedor notará y reiniciará la tarea.
Ahora, hay que señalar que la aplicación de ambas tareas se envolverá el código en run()
en un bucle infinito que nunca se quedará hasta su finalización, con un bloque try/catch que debe manejar todas las excepciones de tiempo de ejecución sin interrumpir el lazo. Estoy tratando de agregar otra capa de certeza; si yo o alguien que me sigue hace algo estúpido que derrota estas salvaguardas y se detiene la tarea, la aplicación debe reaccionar de manera adecuada.
¿Existe una mejor práctica para abordar este problema que la gente más experimentada que yo recomendaría?
Fwiw, he azotado en marcha esta clase de prueba:
public class ExecTest {
private static ExecutorService executor = null;
private static Future results1 = null;
private static Future results2 = null;
public static void main(String[] args) {
executor = Executors.newFixedThreadPool(2);
while(true) {
try {
checkTasks();
Thread.sleep(1000);
}
catch (Exception e) {
System.err.println("Caught exception: " + e.getMessage());
}
}
}
private static void checkTasks() throws Exception{
if (results1 == null || results1.isDone() || results1.isCancelled()) {
results1 = executor.submit(new Test1());
}
if (results2 == null || results2.isDone() || results2.isCancelled()) {
results2 = executor.submit(new Test2());
}
}
}
class Test1 implements Runnable {
public void run() {
while(true) {
System.out.println("I'm test class 1");
try {Thread.sleep(1000);} catch (Exception e) {}
}
}
}
class Test2 implements Runnable {
public void run() {
while(true) {
System.out.println("I'm test class 2");
try {Thread.sleep(1000);} catch (Exception e) {}
}
}
}
Es comportarse de la manera que quiero, pero no sé si hay trampas, ineficiencias, o francamente mala cabeza de espera para sorprenderme (De hecho, dado que soy nuevo en esto, me sorprendería si no fuera algo malo/desaconsejable al respecto.)
Cualquier idea es bienvenida.
Si ejecuta cada una de esas dos tareas que su propio ejecutor de un solo subproceso, sólo puede poner 1000 copias de la tarea en el ejecutor. :-) –
Entonces, si cualquiera de las tareas falla, ¿999 están esperando para tomar su lugar? Je. Lindo, pero créanme, realmente necesito que este tonto sea tan resistente a las balas como pueda. De ahí esta solicitud de esencialmente una revisión del código de la comunidad. – BlairHippo
Bien, sobre el tema de a prueba de balas: ¿cuál es su plan actual para lidiar con tareas que entran en un punto muerto u otras fallas en la vida? El hecho de que pueda reiniciarse una y otra vez no significa que seguirá funcionando, si esos problemas pueden retrasarlos indefinidamente. –