[英]How to wait indefinitely in Java?
我有一個依賴於Timer
和調度的應用程序,而它的 main 方法在執行應用程序設置后什么都不做。
我看到這個成語用了很多:
public static void main(final String[] args) {
// schedule all tasks
while (true) {
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (final InterruptedException ignored) {
Thread.interrupted();
}
}
}
有沒有更好的方法來寫這個? 出於某種原因,我真的需要這個while
循環嗎? (似乎與Thread.interrupted()
有關)
不要自己管理線程。
使用Executors框架創建一對執行器服務。
Runnable
或Callable
在另一個執行器服務上執行。有沒有更好的表達方式?
是的,有更好的方法。
使用執行器框架。 請參閱 Oracle 的教程。
發明了這個框架,因此我們不必直接管理線程。 大多數情況都可以由 Executors 框架處理,只有極少數情況需要程序員來處理線程。
Executors 框架取代了Timer
和TimerTask
類。 如Timer
class Javadoc 中所述:
Java 5.0 引入了 java.util.concurrent package 並且其中一個並發實用程序是以給定速率重復執行任務的 ScheduledThreadPool 或並發實用程序。 它實際上是 Timer/TimerTask 組合的更通用替代品,因為它允許多個服務線程,接受各種時間單位,並且不需要子類化 TimerTask(只需實現 Runnable)。 使用一個線程配置 ScheduledThreadPoolExecutor 使其等效於 Timer。
我假設您嘗試做的是偶爾發現需要完成的任務,然后在后台線程上執行該任務。
為此,我們需要兩個執行器服務,每個服務都由一個線程池支持。
Executors.newCachedThreadPool
使用無界線程池。 我們稱之為我們的workers
執行服務。 如果您有 CPU 密集型任務,您可能需要由配置為最大線程數的線程池支持的替代執行器服務。dispatcher
器。 這是模擬代碼的一個版本,我們碰巧發現每次檢查時只需要完成一個任務。 我們使用一個隨機數來模擬一些被請求的任意任務。 為了保持代碼整潔,我們使用了 Java 14 中的新開關表達式功能。開關中的每個案例都會生成一個可運行的Runnable
,並將該可運行的 ZA8CFDE6331BD59EB26666F89111C4 提交給執行器服務。 執行器服務在提交時立即執行每個可運行的run
方法。 生成匿名Runnable
object 的代碼部分是這個 lambda 語法:
( ) -> System.out.println( "Running Fruit report. Now: " + Instant.now() )
您也可以使用常規語法來生成Runnable
。 您可能希望定義單獨的類來定義您放置任務代碼的Runnable
。
public class FruitReport implements Runnable
{
public void run() {
System.out.println( "Running Fruit report. Now: " + Instant.now() ) ;
}
}
完整的示例代碼。
package work.basil.example;
import java.time.Instant;
import java.util.concurrent.*;
public class TimerTaskManager
{
ExecutorService workers;
ScheduledExecutorService dispatcher;
private void launch ( )
{
System.out.println( "INFO - Method `launch` running at " + Instant.now() );
this.workers = Executors.newCachedThreadPool();
this.dispatcher = Executors.newSingleThreadScheduledExecutor();
this.dispatcher.scheduleWithFixedDelay(
( ) -> {
// Check for whatever input you have that prompts for tasks to be performed.
// We use a random number generator to simulate arbitrary work requests arriving.
// Using the new switch expressions feature in Java 14. https://openjdk.java.net/jeps/361
int r = ThreadLocalRandom.current().nextInt( 1 , 6 ); // inclusive-to-exclusive.
switch ( r )
{
case 1 -> this.workers.submit( ( ) -> System.out.println( "Running Fruit report. Now: " + Instant.now() ) ); // Passing an anonymous `Runnable` object to the `ExecutorService::submit` method.
case 2 -> this.workers.submit( ( ) -> System.out.println( "Running Wine report. Now: " + Instant.now() ) );
case 3 -> this.workers.submit( ( ) -> System.out.println( "Running Clothing report. Now: " + Instant.now() ) );
case 4 -> this.workers.submit( ( ) -> System.out.println( "Running Appliance report. Now: " + Instant.now() ) );
case 5 -> this.workers.submit( ( ) -> System.out.println( "Running Tools report. Now: " + Instant.now() ) );
default -> System.out.println( "ERROR - Unexpected r value: " + r );
}
} ,
3 ,
10 ,
TimeUnit.SECONDS
);
}
private void shutdown ( )
{
this.dispatcher.shutdown();
this.workers.shutdown();
System.out.println( "INFO - Method `shutdown` running at " + Instant.now() );
}
public static void main ( String[] args )
{
TimerTaskManager app = new TimerTaskManager();
app.launch();
try
{
Thread.sleep( TimeUnit.MINUTES.toMillis( 1 ) );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
finally
{
app.shutdown();
}
}
}
跑的時候。
INFO - Method `launch` running at 2020-06-28T04:16:17.742443Z
Running Wine report. Now: 2020-06-28T04:16:20.786653Z
Running Tools report. Now: 2020-06-28T04:16:30.787891Z
Running Appliance report. Now: 2020-06-28T04:16:40.791585Z
Running Wine report. Now: 2020-06-28T04:16:50.796355Z
Running Fruit report. Now: 2020-06-28T04:17:00.800407Z
Running Appliance report. Now: 2020-06-28T04:17:10.805166Z
INFO - Method `shutdown` running at 2020-06-28T04:17:17.783938Z
讓我們稍微復雜一點,以更好地模擬您可能的實際情況,即每次您計划的執行程序服務檢查時都會發現一些任意數量的請求處於待處理狀態。 為了模擬這一點,我們隨機重復 switch 語句。
package work.basil.example;
import java.time.Instant;
import java.util.concurrent.*;
public class TimerTaskManager
{
ExecutorService workers;
ScheduledExecutorService dispatcher;
private void launch ( )
{
System.out.println( "INFO - Method `launch` running at " + Instant.now() );
this.workers = Executors.newCachedThreadPool();
this.dispatcher = Executors.newSingleThreadScheduledExecutor();
this.dispatcher.scheduleWithFixedDelay(
( ) -> {
// Check for whatever input you have that prompts for tasks to be performed.
int countRequests = ThreadLocalRandom.current().nextInt( 1 , 7 );
System.out.println( "INFO - Found " + countRequests + " incoming requests for work to be done. Now: " + Instant.now() );
for ( int i = 1 ; i <= countRequests ; i++ )
{
// We use a random number generator to simulate arbitrary work requests arriving.
// Using the new switch expressions feature in Java 14. https://openjdk.java.net/jeps/361
int r = ThreadLocalRandom.current().nextInt( 1 , 6 ); // inclusive-to-exclusive.
switch ( r )
{
case 1 -> this.workers.submit( ( ) -> System.out.println( "Running Fruit report. Now: " + Instant.now() ) ); // Passing an anonymous `Runnable` object to the `ExecutorService::submit` method.
case 2 -> this.workers.submit( ( ) -> System.out.println( "Running Wine report. Now: " + Instant.now() ) );
case 3 -> this.workers.submit( ( ) -> System.out.println( "Running Clothing report. Now: " + Instant.now() ) );
case 4 -> this.workers.submit( ( ) -> System.out.println( "Running Appliance report. Now: " + Instant.now() ) );
case 5 -> this.workers.submit( ( ) -> System.out.println( "Running Tools report. Now: " + Instant.now() ) );
default -> System.out.println( "ERROR - Unexpected r value: " + r );
}
}
} ,
3 ,
10 ,
TimeUnit.SECONDS
);
}
private void shutdown ( )
{
this.dispatcher.shutdown();
this.workers.shutdown();
System.out.println( "INFO - Method `shutdown` running at " + Instant.now() );
}
public static void main ( String[] args )
{
TimerTaskManager app = new TimerTaskManager();
app.launch();
try
{
Thread.sleep( TimeUnit.MINUTES.toMillis( 1 ) );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
finally
{
app.shutdown();
}
}
}
跑的時候。
INFO - Method `launch` running at 2020-06-28T04:34:52.097616Z
INFO - Found 2 incoming requests for work to be done. Now: 2020-06-28T04:34:55.112823Z
Running Tools report. Now: 2020-06-28T04:34:55.122258Z
Running Appliance report. Now: 2020-06-28T04:34:55.122653Z
INFO - Found 2 incoming requests for work to be done. Now: 2020-06-28T04:35:05.127456Z
Running Appliance report. Now: 2020-06-28T04:35:05.128309Z
Running Clothing report. Now: 2020-06-28T04:35:05.128297Z
INFO - Found 5 incoming requests for work to be done. Now: 2020-06-28T04:35:15.128481Z
Running Tools report. Now: 2020-06-28T04:35:15.129414Z
Running Wine report. Now: 2020-06-28T04:35:15.129430Z
Running Appliance report. Now: 2020-06-28T04:35:15.129663Z
Running Tools report. Now: 2020-06-28T04:35:15.130001Z
Running Fruit report. Now: 2020-06-28T04:35:15.130441Z
INFO - Found 4 incoming requests for work to be done. Now: 2020-06-28T04:35:25.133727Z
Running Clothing report. Now: 2020-06-28T04:35:25.133880Z
Running Wine report. Now: 2020-06-28T04:35:25.133917Z
Running Wine report. Now: 2020-06-28T04:35:25.133967Z
Running Wine report. Now: 2020-06-28T04:35:25.134148Z
INFO - Found 6 incoming requests for work to be done. Now: 2020-06-28T04:35:35.136503Z
Running Tools report. Now: 2020-06-28T04:35:35.136663Z
Running Wine report. Now: 2020-06-28T04:35:35.136733Z
Running Clothing report. Now: 2020-06-28T04:35:35.136764Z
Running Clothing report. Now: 2020-06-28T04:35:35.136735Z
Running Appliance report. Now: 2020-06-28T04:35:35.137363Z
Running Clothing report. Now: 2020-06-28T04:35:35.137349Z
INFO - Found 3 incoming requests for work to be done. Now: 2020-06-28T04:35:45.136728Z
Running Appliance report. Now: 2020-06-28T04:35:45.136943Z
Running Clothing report. Now: 2020-06-28T04:35:45.136940Z
Running Tools report. Now: 2020-06-28T04:35:45.136948Z
INFO - Method `shutdown` running at 2020-06-28T04:35:52.111007Z
注意:確保在不再需要或退出應用程序時正常關閉每個執行程序服務。 否則,它們的后備線程池可能會像僵屍一樣無限期地繼續存在。
注意:將提交給計划執行程序服務的代碼包裝在 try-catch 中,以防出現任何意外異常和可能的錯誤。 如果一個throwable
冒泡到達預定的執行器服務,該服務會默默地停止安排更多的工作。 搜索堆棧溢出以了解更多信息。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.