ExecutorService, Future, Threads появляется Actives, когда все Runnables должны быть завершены - PullRequest
0 голосов
/ 24 сентября 2019

У меня есть сложная программа, использующая Runnable, ExecutorService и Future.

Я хочу знать, почему Runnable / Threads работает и мое приложение все еще работает, когда я надеюсь, что все они должны быть завершены.

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

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;

public class TestFutureExecutorService {

  public static void main(String... args) {

    List<Future<?>> futureList = new ArrayList<>();
    ExecutorService executorService = Executors.newCachedThreadPool();

    RunnableTest rt = new RunnableTest("rt", futureList, executorService);

    new Timer(false).schedule(new TimerTask() {
      @Override
      public void run() {
        rt.stop();
      }
    }, ThreadLocalRandom.current().nextLong(100L, 500L));

    System.out.println("Let's go to check the threads status.\n");
    for (int i = 0; i < futureList.size(); i++) {//Working!
      try {
        if (futureList.get(i) != null) {
          futureList.get(i).get();
        }
      } catch (InterruptedException e) {
        e.printStackTrace();
      } catch (ExecutionException e) {
        e.printStackTrace();
      }
    }
    System.out.println("Apparently everything is finished.\n");

    boolean allDone = true;
    for (int i = 0; i < futureList.size(); i++) {
      if (futureList.get(i) != null) {
        allDone &= futureList.get(i).isDone(); // check if future is done
      }

    }
    System.out.println("Is everything really finished?:" + allDone + ".\n");
    //executorService.shutdown();

    Thread thisThread = Thread.currentThread();
    thisThread.setName("Admin Thread");
    thisThread.setPriority(1);
    System.out.println("Thread = " + thisThread);

    int count = Thread.activeCount();
    System.out.println("currently active threads = " + count);

    Thread activeThreadsArray[] = new Thread[count];
    Thread.enumerate(activeThreadsArray);
    // prints active threads
    for (int i = 0; i < count; i++) {
      System.out.println(i + ": " + activeThreadsArray[i]);
    }

  }

  public static class RunnableTest implements Runnable {
    private final String name;
    private final List<Future<?>> futureList;
    private final ExecutorService executorService;
    private volatile boolean isRunning = false;

    public RunnableTest(String name, List<Future<?>> futureList, ExecutorService executorService) {
      this.name = name;
      this.futureList = futureList;
      this.executorService = executorService;
      this.futureList.add(this.executorService.submit(this));
    }

    @Override
    public void run() {
      Thread.currentThread().setName(Thread.currentThread().getName() + this.getClass().getSimpleName() + ":" + name);
      isRunning = true;
      while (isRunning) {
        try {
          Thread.sleep(50);
          new Processor(this.futureList, this.executorService);
        } catch (Exception ex) {
          Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
        }
      }
        System.out.println("Finishing:" + Thread.currentThread().getName());
    }

    public void stop() {
      isRunning = false;
    }

  }

  public static class Processor implements Runnable {

    private final List<Future<?>> futureList;
    private final ExecutorService executorService;

    public Processor(List<Future<?>> futureList, ExecutorService executorService) {
      this.futureList = futureList;
      this.executorService = executorService;
      this.futureList.add(this.executorService.submit(this));
    }

    @Override
    public void run() {
      String hour = new SimpleDateFormat("_yyyyMMdd-HHmmss.SSSS_").format(new Date());
      Thread.currentThread().setName(hour + this.getClass().getSimpleName());
        try {
          int timeSleeping = ThreadLocalRandom.current().nextInt(100, 300);
          Thread.sleep(timeSleeping);
        } catch (Exception ex) {
          Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
        }
        System.out.println("Finishing:" + Thread.currentThread().getName());
    }
  }

}

Теперь вывод ....

Let's go to check the threads status.

Finishing:_20190923-203808.0435_Processor
Finishing:_20190923-203808.0437_Processor
Finishing:_20190923-203808.0489_Processor
Finishing:pool-1-thread-1->RunnableTest:rt
Finishing:_20190923-203808.0695_Processor
Finishing:_20190923-203808.0544_Processor
Finishing:_20190923-203808.0593_Processor
Finishing:_20190923-203808.0746_Processor
Finishing:_20190923-203808.0645_Processor
Apparently everything is finished.

Is everything really finished?:true.

Thread = Thread[Admin Thread,1,main]
currently active threads = 8
0: Thread[Admin Thread,1,main]
1: Thread[pool-1-thread-1->RunnableTest:rt,5,main]
2: Thread[Timer-0,5,main]
3: Thread[_20190923-203808.0593_Processor,5,main]
4: Thread[_20190923-203808.0695_Processor,5,main]
5: Thread[_20190923-203808.0746_Processor,5,main]
6: Thread[_20190923-203808.0544_Processor,5,main]
7: Thread[_20190923-203808.0645_Processor,5,main]

Когда я запускаю приложение, в моей IDE остается что-то «работающее», но все Runnable должны быть завершены!

Почему Threads кажется активным? Что означаетчто?

Как все заканчивается?

1 Ответ

0 голосов
/ 24 сентября 2019

Вы используете ExecutorService.ExecutorService поддерживает потоки живыми, чтобы быть готовыми к следующим задачам.Вы должны сообщить ExecutorService, что у вас больше нет задачи, и она может отбрасывать потоки.

Вы можете сделать это, вызвав метод

 `shutdown() or shutdownNow()`

Так что раскомментируйте строку в своем коде послепроверка готовности:

 System.out.println("Is everything really finished?:" + allDone + ".\n");
    //executorService.shutdown();

Ваше приложение по-прежнему не будет завершено, поскольку вы создаете поток таймера как поток не-deamon, это означает, что JVM не остановится, если в вашем приложении есть запущенный поток не-deamon.

Вы можете создать таймер в виде нити демона, например:

new Timer(true).schedule(new TimerTask() {
...