Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

308
Views
¿Cómo elimino un Java Future?

El servicio en el que estoy trabajando utiliza un futuro para ejecutar varias tareas en paralelo; cada tarea puede tardar hasta un minuto en completarse. Sin embargo, parece que la biblioteca externa tiene errores, ya que en algunas ocasiones (2% de las veces) no regresa. En esos casos, me gustaría dar un tiempo de espera de 2 minutos, y si no ha regresado, me gustaría matar el futuro y volver a programar más tarde (eventualmente tendrá éxito).

¿Cómo mato al futuro?

 private void run() { ExecutorService queue = Executors.newFixedThreadPool(1); Future<Integer> f = queue.submit(new MyTask()); Thread.sleep(500); try { Integer r = f.get(120, TimeUnit.SECONDS); } catch (InterruptedException | ExecutionException | TimeoutException e) { e.printStackTrace(); f.cancel(true); } // Bad future still running here and I need it dead. } private class MyTask implements Callable<Integer> { private ExternalLibrary extlib = new ExternalLibrary(); @Override public Integer call() throws Exception { // step 1 - do a few things // step 2 - process data Integer val = this.extlib.doSomething(); // here's the problem! // step 3 - do other things return val; } }

Puedo ver la biblioteca externa ejecutándose y consumiendo CPU (durante 24 horas)... sin hacer nada. Es una tarea simple que nunca debería tomar más de 60 segundos para completar su trabajo.

Hasta ahora, estoy matando toda la JVM una vez al día para deshacerme de este problema, pero estoy seguro de que debe haber una mejor manera. Me pregunto cómo los servidores de aplicaciones (Tomcat, JBoss, Weblogic, etc.) lo hacen con procesos no autorizados.

over 4 years ago · Santiago Trujillo
6 answers
Answer question

0

En su código, la llamada:

 this.extlib.doSomething()

debe ser síncrono, porque si no lo es, el código pierde sentido. Con esa suposición, puedes probar:

 ExecutorService executor = Executors.newSingleThreadExecutor(); Future<Integer> future = executor.submit(new MyTask()); try { future.get(120, TimeUnit.SECONDS); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } catch (TimeoutException e) { future.cancel(true); } finally { executor.shutdownNow(); }

Si esto no detiene el trabajo de doSomethig es porque doSomething función está abriendo otros subprocesos para hacer el trabajo. En ese caso, tal vez pueda verificar los hilos que se están ejecutando con:

 Thread.getAllStackTraces()

Y trata de matar al correcto...

over 4 years ago · Santiago Trujillo Report

0

Incluso si pudiera matar el futuro colgado en la biblioteca de buggy, es probable que esto no resuelva su problema. Es posible que la biblioteca aún haya adquirido algún recurso que no se limpiará correctamente. Esto podría ser asignaciones de memoria, identificadores de archivos abiertos o incluso monitores que dejan algunas estructuras de datos internas en un estado inconsistente. Eventualmente, es probable que regrese al punto en el que tiene que reiniciar su JVM.

Básicamente hay dos opciones: arreglarlo o aislarlo .

  1. Arreglo: intente arreglar la biblioteca. Si esto no es posible,
  2. aislar: aislar la biblioteca en un servicio externo del que depende su aplicación. Por ejemplo, implemente una API REST para llamar a la biblioteca y envuelva todo en una imagen de Docker. Automatice el reinicio del contenedor Docker según sea necesario.
over 4 years ago · Santiago Trujillo Report

0

Como han mencionado otros, detener un Future es cooperativo, lo que significa que el subproceso que se ejecuta de forma asíncrona debe responder a la cancelación del subproceso en espera. Si la tarea asíncrona no es cooperativa, simplemente invocar shutdown o shutdownNow no será suficiente, ya que el TPE subyacente solo interrupt los subprocesos.

Si no tiene control sobre extlib y extlib no coopera, veo dos opciones

  1. Puede stop el hilo que se está ejecutando actualmente. Esto puede causar problemas si el subproceso que se detiene actualmente tiene un bloqueo o algún otro recurso. Puede conducir a errores interesantes que podrían ser difíciles de analizar.
  2. Esto podría requerir más trabajo, pero podría ejecutar la tarea asíncrona como un proceso completamente separado. El TPE aún puede ejecutar el proceso y, en caso de interrupción, puede destroy el proceso. Obviamente, esto tiene problemas más interesantes, como cómo cargar el proceso con la entrada requerida.
over 4 years ago · Santiago Trujillo Report

0

Desafortunadamente, si la biblioteca externa no está cooperando con las interrupciones de subprocesos, no hay nada que pueda hacer para eliminar el Thread que ejecuta la tarea administrada por ExecutorService .

Una alternativa que se me ocurre es ejecutar el código ofensivo como un proceso separado. Con ProcessBuilder y Process , su tarea puede controlar (o) incluso eliminar el proceso ofensivo después de un tiempo de espera ( https://docs.oracle.com/javase/9/docs/api/java/lang/Process.html#destroyForcably- - ).

Consulte también https://docs.oracle.com/javase/9/docs/api/java/lang/ProcessBuilder.html

over 4 years ago · Santiago Trujillo Report

0

@joe Eso es correcto. A menos que tenga control sobre el hilo y dentro del hilo, no puede matarlo.

 this.extlib.doSomething();

si esta línea inicia un subproceso, entonces debemos apoderarnos de ese subproceso para eliminarlo, ya que no tenemos una referencia para detenerlo.

over 4 years ago · Santiago Trujillo Report

0

Si entiendo su requisito correctamente y según su requisito (es decir, 1 subproceso), puede buscar cerrar el servicio de executorservice en 2 fases, el código está disponible en Java doc de executorservice:

 try { Integer r = f.get(120, TimeUnit.SECONDS); } catch (InterruptedException | ExecutionException | TimeoutException e) { e.printStackTrace(); //f.cancel(true); you can omit this call if you wish. shutdownAndAwaitTermination(queue); } ... //remaining method code void shutdownAndAwaitTermination(ExecutorService pool) { pool.shutdown(); // Disable new tasks from being submitted try { // Wait a while for existing tasks to terminate if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { pool.shutdownNow(); // Cancel currently executing tasks // Wait a while for tasks to respond to being cancelled if (!pool.awaitTermination(60, TimeUnit.SECONDS)) System.err.println("Pool did not terminate"); } } catch (InterruptedException ie) { // (Re-)Cancel if current thread also interrupted pool.shutdownNow(); // Preserve interrupt status Thread.currentThread().interrupt(); } }

Lea la documentación sobre shutdown() , shutdownNow() cómo se comportan porque menciona claramente que no hay una garantía del 100% de que las tareas/executorservice se detengan si se están ejecutando.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!