[英]Executor Shutdown await termination not working
我正在調用等待終止,因為我需要在調用意圖之前完成前兩個 Runnables。 但是它不起作用,意圖被調用,當我調用 navEngine.getRoutes 時,navEngine 是 null。 執行器服務初始化如下:
public static ExecutorService buildExecutor = Executors.newFixedThreadPool(2);
Runnable runnable = new Runnable() {
@Override
public void run() {
navEngine = new NavigationManager(start, destination, selectedBuilding);
}
};
buildExecutor.execute(runnable);
Boolean isVisionImpaired = defaultPreferences.getString(kSightSetting, "Vision Impaired").equalsIgnoreCase("Vision Impaired");
if (isVisionImpaired) {
Runnable dRunnable = new Runnable() {
@Override
public void run() {
String[] dxfs = mapManager.generateDs( new String[] { selectedBuilding.getBuildingID() });
navEngine.setD_for_these_buildings(dxfs);
}
};
buildExecutor.execute(dRunnable);
}
}
buildExecutor.shutdown();
try {
buildExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
Intent intent = new Intent(ChooseDestinationActivity.this, DefineRouteActivity.class);
任何建議都會很棒。
我已經看了一些可能的解決方案,它們是:
增加等待終止時間
將 try/catch 替換為
while (.buildExecutor;isTerminated()). { //do nothing } Intent(...)
創建可調用列表添加在此處使用 Executors.callable 添加您的可運行對象,然后調用 invokeAll()
List<Callable<Object>> calls = new ArrayList<Callable<Object>>(); calls.add(Executors.callable(your runnable here)); buildExecutor.invokeAll(calls); buildExecutor.shutdown(); Intent(...)
PS我不是本地人並發,但我已經嘗試了我給出的所有解決方案,我也很感激所有建議)
警告:我不做 Android 工作。 我說的是標准 Java。
您的 runnables 和 executor 服務的基礎是正確的。 下面是您的代碼的簡化版本來說明這一點。
所以我懷疑你的問題出在其他地方。 您沒有顯示代碼的所有重要部分。 特別缺乏的是navEngine
的定義,這似乎是您投訴的根源。
package work.basil.example.threading;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class App
{
public static void main ( String[] args )
{
App app = new App();
app.demo();
}
private void demo ( )
{
System.out.println( "`demo` method ending. " + Instant.now() );
ExecutorService executorService = Executors.newFixedThreadPool( 2 );
// Navigation Manager work.
Runnable navManTask = new Runnable()
{
@Override
public void run ( )
{
System.out.println( "navManTask - beginning. Will sleep to simulate lengthy work. " + Instant.now() );
try
{
Thread.sleep( Duration.ofSeconds( 10 ).toMillis() );
}
catch ( InterruptedException e )
{
System.out.println( "navManTask - sleep interrupted. Ending this task prematurely. " + Instant.now() );
return;
}
System.out.println( "navManTask - ending. " + Instant.now() );
}
};
executorService.execute( navManTask );
// Vision Impaired work.
boolean isVisionImpaired = true;
if ( isVisionImpaired )
{
Runnable visionTask = new Runnable()
{
@Override
public void run ( )
{
System.out.println( "visionTask - beginning. Will sleep to simulate lengthy work. " + Instant.now() );
try
{
Thread.sleep( Duration.ofSeconds( 10 ).toMillis() );
}
catch ( InterruptedException e )
{
System.out.println( "visionTask - sleep interrupted. Ending this task prematurely. " + Instant.now() );
return;
}
System.out.println( "visionTask - ending. " + Instant.now() );
}
};
executorService.execute( visionTask );
System.out.println( "`demo` method asking executor service to shut down. " + Instant.now() );
executorService.shutdown();
try
{
System.out.println( "`main` method waiting for the executor service to shut down. " + Instant.now() );
executorService.awaitTermination( 30 , TimeUnit.SECONDS );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
System.out.println( "`demo` method ending. " + Instant.now() );
}
}
}
您可能還有其他並發問題。
navEngine
object 您有兩個同時訪問同一資源的線程,即變量navEngine
。 那里有兩個問題:可見性和線程安全。
Visibility under the Java Memory Model is where a primitive or object reference accessed across threads may show two different cached values. 一種解決方案是volatile
關鍵字。 另一種解決方案可能是Atomic…
class。 搜索以了解有關可見性問題的更多信息。
我們看不到 navEngine 后面的navEngine
。 但是,如果 class 的 object 可以跨線程操作,則必須使 class 成為線程安全的。
在一個線程的代碼中,您正在實例化一個 object 以放置在navEngine
變量中。 在另一個線程的代碼中,您假設 object 存在。 但是您無法預測線程將以什么順序進行工作。 線程的調度實際上是任意且不可預測的,具體取決於主機操作系統和JVM的瞬時條件和 CPU 調度決策策略。 在第一個線程使用 object 引用填充變量之前,第二個線程完全有可能嘗試訪問navEngine
。
由於第二個 runnable 取決於第一個是否完整且成功,因此擁有兩個單獨的線程是沒有意義的。 您不妨將兩者組合成一個Runnable
任務。
如果您堅持使用這兩個線程,那么您將需要將您的調用更改為execute
submit
。 submit
方法返回一個Future
object。 您可以使用這個Future
object 來檢查第一個任務是否成功。
這是上面修改的代碼,用於捕獲提交 navMan 任務到執行器服務時返回的Future
。 視覺工作等待Future
發出 navMan 工作完成的信號。
package work.basil.example.threading;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.*;
public class App
{
public static void main ( String[] args )
{
App app = new App();
app.demo();
}
private void demo ( )
{
System.out.println( "`demo` method ending. " + Instant.now() );
ExecutorService executorService = Executors.newFixedThreadPool( 2 );
// Navigation Manager work.
Runnable navManTask = new Runnable()
{
@Override
public void run ( )
{
System.out.println( "navManTask - beginning. Will sleep to simulate lengthy work. " + Instant.now() );
try
{
Thread.sleep( Duration.ofSeconds( 10 ).toMillis() );
}
catch ( InterruptedException e )
{
System.out.println( "navManTask - sleep interrupted. Ending this task prematurely. " + Instant.now() );
return;
}
System.out.println( "navManTask - ending. " + Instant.now() );
}
};
Future < String > navManFuture = executorService.submit( navManTask , "whatever" );
// Vision Impaired work.
boolean isVisionImpaired = true;
if ( isVisionImpaired )
{
Runnable visionTask = new Runnable()
{
@Override
public void run ( )
{
System.out.println( "visionTask - beginning. Will sleep to simulate lengthy work. " + Instant.now() );
if ( navManFuture.isCancelled() )
{
System.out.println( "visionTask - Found the navMan task got cancelled. Ending this task prematurely. " + Instant.now() );
return;
}
try
{
System.out.println( "visionTask - Waiting for the navMan task to be done. " + Instant.now() );
String whatever = navManFuture.get(); // Wait for `namManTask` to get done. This code blocks here, waiting.
Thread.sleep( Duration.ofSeconds( 10 ).toMillis() );
}
catch ( InterruptedException e )
{
System.out.println( "visionTask - sleep interrupted. Ending this task prematurely. " + Instant.now() );
return;
}
catch ( ExecutionException e )
{
e.printStackTrace();
}
System.out.println( "visionTask - ending. " + Instant.now() );
}
};
executorService.submit( visionTask );
System.out.println( "`demo` method asking executor service to shut down. " + Instant.now() );
executorService.shutdown();
try
{
System.out.println( "`main` method waiting for the executor service to shut down. " + Instant.now() );
executorService.awaitTermination( 30 , TimeUnit.SECONDS );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
System.out.println( "`demo` method ending. " + Instant.now() );
}
}
}
順便說一句,如果Project Loom技術在 Java 到來時,這里看到的代碼會更簡單。 在 Loom 中, ExecutorService
接口也是AutoCloseable
。 這意味着我們可以使用方便的 try-with-resources 語法。 close
方法會阻塞,直到所有提交的任務都完成/失敗/取消。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.