2017-07-11 44 views
0

當用戶按下Enter或其他線程完成其工作時,我需要退出應用程序。我在過去做到了這一點的方法是如下:Java如何等待直到線程退出或用戶按下輸入

// Main 
final Worker worker = new Worker(); 
final Thread workerThread = new Thread(worker::run); 
workerThread.start(); 
try { 
    System.in.read(); 
} catch (final IOException e) { 
    // The worker thread finished executing 
} 

// Worker::run 
public void run() { 
    ... 
    System.in.close(); 
} 

此之前似乎運作得很好,但最近進行一些重構後破門。現在,在另一個線程中調用System.in.close()時,該線程在本地方法close0中無限期地在FileInputStream :: close中掛起。任何人都可以解釋爲什麼這種方法調用會無限期地掛起,就好像存在死鎖情況一樣?

我對此有一個變通,這是如下:

// Main.java 
private static final Object waitObject = new Object(); 

private static boolean isRunning = true; 

private static void notifyWaitObject() { 
    synchronized (waitObject) { 
     isRunning = false; 
     waitObject.notify(); 
    } 
} 

public static void main(final String[] args) { 
    // Create a thread to wait until enter is pressed 
    final Thread waitThread = new Thread(() -> { 
     try { 
      System.in.read(); 
     } catch (final IOException e) { 
      // Eat the exception 
     } finally { 
      notifyWaitObject(); 
     } 
    }, "User Input Thread"); 
    waitThread.setDaemon(true); 
    waitThread.start(); 

    // Create a worker thread 
    final Worker worker = new Worker(); 
    final Thread workerThread = new Thread(() -> worker.run(Main::notifyWaitObject)); 
    workerThread.start(); 

    // Wait until either the worker threads are done, or enter is pressed 
    synchronized (waitObject) { 
     if (isRunning) waitObject.wait(); 
    } 
} 

// Worker.java 
public void run(final Runnable exitNotifier) { 
    ... 
    exitNotifier.run(); 
} 

然而,上述似乎不必要的沉重的東西,這似乎應該是比較簡單的。有誰知道更好的方式來實現這個線程安全的方式?

+0

@Holger我已經更新了這個問題,用我實際上最終實現的代碼替換了我的「名義上的」解決方法代碼。 –

回答

1

我不知道有任何可靠的方法來停止執行舊的java.io流的I/O操作的線程,afaik從來沒有工作過。但是,既然你說,你要退出應用程序,如果不是,工人或I/O完成,你可以用:當任一工作已經完成

ExecutorService es = Executors.newFixedThreadPool(2); 

es.invokeAny(Arrays.asList(
    () -> { worker.run(); return null; }, 
    () -> System.in.read())); 

es.shutdown(); 
System.exit(0); 

invokeAny將返回,甚至取消其他在中斷的情況下,它支持它。

請注意,由於停止System.in.read()操作實際上並不成功,因此如果未提供任何控制檯輸入,將會有一個懸掛工作線程仍在執行System.in.read(),但退出JVM將終止所有線程。

相關問題