[英]How to keep thread waiting in ScheduledExecutorService that has been shutdown
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;
}
當我分析應用程序時,我注意到這個方法創建的調度線程在執行之前總是處於“正在運行”而不是“等待”狀態。 如果我刪除executorService.shutdown()它會做我想要的(即線程保持等待狀態,直到它們運行的時間)。 但是,如果沒有executorService.shutdown(),nonDaemon線程在執行后永遠不會被垃圾收集。 有沒有辦法可以確保線程在執行前始終處於等待狀態? 或者我可以使用其他替代方法來確保:
線程沒有等待因為你沒有調用future.get()方法。 我做了一個單元測試來證明這一點。
測試#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
我希望它對你有所幫助!
您所看到的是ScheduledExecutor委托給普通的ThreadPoolExecutor以獲取關閉功能。 關閉TPE時,其所有線程都會在后備工作隊列中旋轉,直到它為空。 那么ScheduledThreadPool使用的DelayedQueue可能不是空的,但是如果你進行了輪詢,你會得到一個空值,因為任務還沒有准備好安排。 它會旋轉並旋轉直到准備好
你唯一能做的就是shutdownNow並執行以其他方式返回的任務。
我也被告知這實際上是在Java 7中修復的
找出一個解決方案:它是shutdown(),它將所有待處理任務線程的狀態從“等待”更改為“正在運行”。 我現在使用executorService來調度自己的shutdown(),而不是立即調用shutdown()。 這可確保掛起的任務盡可能長時間保持等待狀態 - 從而節省CPU資源。
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;
}
跑你的代碼。 這是來自jvisualvm中的線程轉儲(我命名為線程“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
現在,這是來自於ThreadPoolExecutor.java:950
grepcode:
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();
這讓我得出結論,問題出在您的測試代碼中 - 您正在關閉執行程序太快,並且線程發現自己處於一種奇怪的狀態。 這不應該是生產代碼中的問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.