2013-10-14 2 views
1

Я могу много раз задавать этот вопрос. Извиняюсь за то, что снова попросил об этом. У меня странная проблема.Завершение Java-Thread

У меня есть работа, которая отправляет тысячи рабочих мест через ExecutorService в качестве отдельной задачи Runnable. Это делается в простой петле. Конец цикла for, я вызываю service.shutdown() и за ним следует waitTermination.

Поскольку количество подаваемых нитей огромно, потоки сохраняются до тех пор, пока не будут представлены все задачи.

Есть ли способ, эти потоки могут быть прекращены изящно, как только его исполнение закончено?

+0

Если вы звоните 'ExecutorService.shutdown()' ExecutorService остановит все свои темы (позволяя им возвращаться из своих методов запуска), когда все задания завершены. – Dev

+0

Thanks Dev. Есть ли способ закрыть поток, как только его выполнение будет завершено, а не ждать окончания всех остальных потоков? – user1401472

+0

Выполнение выполнения потоковой работы или потоков не завершено до тех пор, пока «ExecutorService» не будет остановлено. Потоки обычно используются повторно для нескольких заданий. Если вы хотите завершить работу «ExecutorService» после завершения определенного задания, вы можете заблокировать «Будущее» для этого задания и «shutdownNow()» исполнитель, когда он вернется. – Dev

ответ

1

Вы можете создать новый ThreadPoolExecutor без вызова java.util.concurrent.Executors:

int corePoolSize = 0; 
    int maximumPoolSize = 64; 
    int keepAliveTime = 5000; 
    ExecutorService executorService = 
      new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, 
        TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>()); 

Из Javadoc: «Если в настоящее время бассейна имеет более corePoolSize нитей, избыточные потоки будут прекращены, если они простаивают более чем KeepAliveTime»

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html

Edit:

Вот небольшой пример, если вы запустите в отладочной среде Eclipse, вы должны видеть потоки приходят и уходят:

import java.util.Random; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.SynchronousQueue; 
import java.util.concurrent.ThreadPoolExecutor; 
import java.util.concurrent.TimeUnit; 


public class ExecutorTest { 

    public static void main(String[] args) { 

     ExecutorService executorService = new ThreadPoolExecutor(0, 64, 1000, 
         TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>()); 

     for (int i = 0; i <= 500; i ++) { 

      try { 
       Thread.sleep(new Random().nextInt(200)); 
      } catch (InterruptedException e) { 
      } 

      executorService.submit(new TestTask()); 
     } 
    } 

    public static class TestTask implements Runnable { 
     public void run() { 
      try { 
       Thread.sleep(new Random().nextInt(1500)); 
      } catch (InterruptedException e) { 
      } 
     } 
    } 
} 
+0

KeepAilveTime не работал для меня. Мне показалось, что после 30 секунд, которые я указываю как keepAliveTime, среда отладки eclipse не должна показывать поток. Но этого не произошло. Я все еще вижу поток в прямом эфире, хотя он не обрабатывается.Я знаю, что поток должен быть безвредным, но я не хочу слишком много болтающихся потоков в моем приложении. Я что-то упускаю? – user1401472

+1

Возможно, ваш параметр «corePoolSize» слишком высок? –

0

Правильно, что shutdownNow() позволит вам прекратить выполнение с ожидающими выполнения задач. Если ваша цель - сделать достаточно работы, чтобы вычислить некоторый результат (который будет принимать неопределенное количество задач), но перестаньте делать больше работы, как только у вас получится результат, тогда вам понадобится какой-то способ для объектов Runnable, чтобы сигнализировать петлю, чтобы она прекратила цикл. Что-то вроде:

ExecutorService svc = ... 
AtomicBoolean done = new AtomicBoolean(); 
for (int i=0; i < jobs.length; i++) { 
    svc.submit(new MyRunnable(done, jobs[i])); 
    if (done.get()) break; 
} 

class MyRunnable implements Runnable { 
    private final Whatever job; 
    private final AtomicBoolean done; 
    MyRunnable (AtomicBoolean done, Whatever job) { this.done = done; this.job = job; } 
    public void run() { 
    if (done).get() return; 
    //do the work 
    if (somehowComputeThatTheWorkIsComplete) done.set(true); 
    } 
} 

Если что-то висит, потому что слишком много потоков запускаются, а затем рассмотреть вопрос об использовании Executors.newFixedThreadPool() - компьютер фактически не может больше работать одновременно, чем количество имеющихся логических ядер. Таким образом, использование неограниченного пула потоков (может создавать до Integer.MAX_VALUE потоков) не полезно, потому что на самом деле это не дает вам больше параллелизма. Просто ограничьте исполнителей разумным количеством потоков, и проблемы с зависанием, вероятно, исчезнут.

+0

Спасибо Тим. Это точно такая же проблема, о которой вы говорили. Я не хочу, чтобы потоки, завершившие их выполнение, были живы. Каждый поток уже собирает требуемые результаты в отдельной коллекции, и эти потоки больше не нужны. Поэтому, даже если я использую fixedThread, он все равно будет ждать завершения других потоков до завершения. – user1401472

Смежные вопросы