How to save a pending thread in a ScheduledExecutorService that has been disabled

public ScheduledFuture<?> executeTaskWithDelay(String name, 
      final Runnable runnable, Period delay, boolean isDaemon) {
  ScheduledExecutorService executorService = 
        Executors.newSingleThreadScheduledExecutor(new DefaultThreadFactory(
          name, isDaemon));
  ScheduledFuture<?> future =  executorService.schedule(runnable, 
        delay.toStandardDuration().getMillis(), TimeUnit.MILLISECONDS);
  executorService.shutdown(); 
  return future;
}

When I was profiling the application, I noticed that the scheduled threads created by this method are always in the "Run" state, and not "Wait" before they are executed. If I delete executorService.shutdown (), it does what I want (that is, the threads remain in a wait state until it is time to start them). However, without executorService.shutdown (), nonDaemon threads never receive garbage collection after execution. Is there a way to ensure that threads are always in a wait state before execution? or what other replacement can I use for this method to make sure that:

  • I can attach a prefix to the names of the threads that are executed in the executing service (which is efficient, which does the implementation of DefaultThreadFactory)
  • Non-daemon threads receive GC after execution.
  • created Themes remain on hold until it is time to launch them.
+5
source share
4 answers

The solution was clarified: This is shutdown (), which changes the state of all pending task flows from "wait" to "start". Instead of calling shutdown () immediately, I now use the executorService function to schedule a call to its own completion (). This ensures that pending tasks remain on hold for as long as possible, thereby conserving CPU resources.

public ScheduledFuture<?> executeTaskWithDelay(String name, 
      final Runnable runnable, Period delay, boolean isDaemon) {
  final ScheduledExecutorService executorService =  
        Executors.newSingleThreadScheduledExecutor(new DefaultThreadFactory(
      name, isDaemon));
  ScheduledFuture<?> future =  executorService.schedule(runnable, 
        delay.toStandardDuration().getMillis(), TimeUnit.MILLISECONDS);

  executorService.schedule(new Runnable() {
      @Override
      public void run() {
        executorService.shutdown();
      }}, delay.toStandardDuration().getMillis(), TimeUnit.MILLISECONDS);

  return future;
}
+2
source

, future.get(). unit test, .

№ 1 ( future.get()):

@Test
public void testSchedule() throws InterruptedException, ExecutionException {

    ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
    System.out.println(new Date());
    ScheduledFuture<?> future =  executorService.schedule(new Runnable() {

        public void run() {
            System.out.println(Thread.currentThread().getId() + " - " + Thread.currentThread().getName() + " - Executing thread...");                
        }

    }, 5, TimeUnit.SECONDS);

    //System.out.println("future : " + future.get());

    executorService.shutdown();
    System.out.println(new Date());
}

:

Thu May 24 10:11:14 BRT 2012
Thu May 24 10:11:14 BRT 2012

№ 2 ( future.get()):

@Test
public void testSchedule() throws InterruptedException, ExecutionException {

    ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
    System.out.println(new Date());
    ScheduledFuture<?> future =  executorService.schedule(new Runnable() {

        public void run() {
            System.out.println(Thread.currentThread().getId() + " - " + Thread.currentThread().getName() + " - Executing thread...");                
        }

    }, 5, TimeUnit.SECONDS);

    System.out.println("future : " + future.get());

    executorService.shutdown();
    System.out.println(new Date());
}

:

Thu May 24 10:12:48 BRT 2012
8 - pool-1-thread-1 - Executing thread...
future : null
Thu May 24 10:12:53 BRT 2012

, !

+3

, , - ScheduledExecutor ThreadPoolExecutor . TPE, , . , ScheduledThreadPool DelayedQueue, , , , . ,

, , shutdownNow , .

I was also told that this is really fixed in Java 7

+2
source

Run your code. This is from a stream dump in jvisualvm (I called the stream "bla"):

"bla" prio=5 tid=7fa2bc16a000 nid=0x10bd53000 runnable [10bd52000]
  java.lang.Thread.State: RUNNABLE
  at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:950)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
  at java.lang.Thread.run(Thread.java:680)

  Locked ownable synchronizers:
    - None

Now this is from grepcode for this ThreadPoolExecutor.java:950:

944         // It is possible (but unlikely) for a thread to have been
945         // added to workers, but not yet started, during transition to
946         // STOP, which could result in a rare missed interrupt,
947         // because Thread.interrupt is not guaranteed to have any effect
948         // on a non-yet-started Thread (see Thread#interrupt).
949         if (runStateOf(ctl.get()) == STOP && ! t.isInterrupted())
950             t.interrupt();

This leads me to the conclusion that the problem is in your test code - you finish the executor too quickly, and the thread is in a strange state. This should not be a problem in production code.

0
source

All Articles