簡體   English   中英

Java中的中斷線程

[英]Interrupt Thread in java

我有一種情況,我正在使用線程,她調用了一個可以執行多個進程的方法,我需要使用“取消”按鈕來停止線程,而我不能使用:“ while”,以驗證它已被取消,因為它在此過程中沒有循環。

例如:

    Task<Void> task = new Task<Void>() {
        @Override
        protected Void call() throws Exception {
            controller = new FirstEtapaController();
            execProcess();              
            return null;
        }
    };
    new Thread(task).start();

通話方式

   private void execProcess() {
   Thread thread = new Thread(new Runnable() {

        public void run() {
    getController().execMhetod();
    refreshTable();
        }
    });
    thread.start();
    thread.join();
};

即,即使“ ExecMethod” 已在運行 ,我也需要停止該過程,這將需要幾分鍾的時間,因此我必須停止該過程, 而不必等待他完成 ,否則其他操作不會繼續。

請記住,此過程將與我的DAO一起進行迭代。

唯一的方法(行為良好的方法)是在生成的線程中添加邏輯點以檢查中斷狀態。 您可以選擇使用內置的Thread.interrupt()機制,也可以使用某種形式的線程安全變量( AtomicBoolean ?)或某種信號量來添加自己的邏輯。

如果使用Thread.interrupt()則子進程在遇到某些條件時會拋出InterruptedException,例如Thread.wait()和其他需要同步或使用java.util.concurrent。*類的方法。

無論如何,您都將(應該已經)處理線程中的InterruptedExceptions ,但是也許您需要在子進程中進行常規的“檢查”以尋找中斷狀態(可以使用Thread.isInterrupted() )。

值得閱讀Java中的Handling InterruptedException

如果使用ExecutorService而不是原始線程,則會導致很多其他方法/杠桿來控制線程,其中之一是shutdownAll() ,它使用Thread.interrupt()殺死線程並讓您檢查通過isTerminated()線程狀態

您的用戶界面不必等待工作線程完成,因此不必為此太擔心。

遺憾的是,由於錯誤的實現,不贊成使用Thread.destroy()和Thread.stop()。 我認為Java線程沒有很好的“信號消除”類型的替代品。 如果這很重要,您將必須重新編碼工作程序以檢查某種中止標志。 否則,只需浪費一點CPU。 (實際上,“您無法取消該保存-我已經完成了!”)

一個任務是否可以取消實際上取決於它的實現。 通常,它間歇性地檢查標志是否應該繼續。

您可以自己實現這樣的標志,以及設置它的方法:

private volatile boolean shouldStop;

public void cancel() {
    shouldStop = true;
}

@Override
public void run() {
    while (!shouldStop) {
        // do work
    }
}

但是線程已經帶有一個標志:被中斷的標志。 盡管不必將其用於取消線程,但通常將其用於特定目的。 實際上,標准的ExecutorService實現將嘗試通過中斷線程來取消它們的線程。

除此之外,當線程被InterruptedException時,幾種阻塞方法(將線程置於BLOCKEDWAITING狀態的方法)將引發InterruptedException ,這時它們再次變為RUNNABLE 這是以前帶有布爾標志的方法無法實現的。

因此,使用中斷來取消任務是一種更好的方法。 而且您實際上也不再需要那種cancel()方法:

@Override
public void run() {
    while (!Thread.currentThread().isInterrupted()) {
        // do work
    }
}

另外,任何知道您的線程的代碼都知道如何取消它。 包括標准的ExecutorService實現。

捕獲InterruptedException時應格外小心,因為這樣做會清除被中斷的標志。 建議總是在捕獲到異常時恢復中斷的標志,因此客戶也知道是時候停止做他們正在做的事情了。

private BlockingQueue<Integer> queue;

@Override
public void run() {
    while (!Thread.currentThread().isInterrupted()) {

        try {
            Integer id = queue.take(); // blocking method

            // do work
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

    }
}

要取消線程,只需保留對Thread對象的引用並在其上調用interrupt()

Thread thread = new Thread(new InterruptibleTask());
thread.start();

// some time after :

thread.interrupt();

但是,一種更優雅的方法是通過Future對象來監視任務(而不是運行任務的特定線程)。 您可以通過在FutureTask包裝RunnableCallable來實現。

RunnableFuture<Void> task = new FutureTask<>(new InterruptibleTask(), null);
new Thread(task).start();

// some time after :

task.cancel(true); // true indicating interruption may be used to cancel.

Future是控制任務的關鍵。 它允許您等待其完成,並有選擇地接收任務計算出的值:

try {
    String value = future.get(); // return value is generically typed String is just as example.
} catch (InterruptedException e) {
    Thread.currentThread().interrupt(); // since future.get() blocks
} catch (ExecutionException e) {
    logger.log(Level.SEVERE, "Exception on worker thread", e.getCause()); // the ExecutionException's cause is the Exception that occurred in the Task
}

如果您有多個任務(甚至只有一個),那么值得使用ExecutorService:

ExecutorService pool = Executors.newCachedThreadPool();

Future<?> submit = pool.submit(new InterruptibleTask());

pool.shutdownNow(); // depending on ExecutorService implementation this will cancel all tasks for you, the ones Executors returns do.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM