簡體   English   中英

Java ExecutorService-為什么該程序保持運行?

[英]Java ExecutorService - why does this program keep running?

我正在嘗試構建類似后台任務執行程序的東西,如果沒有答案,該代碼將在一定時間后終止后台任務(后台任務調用webservices,它們可能會超時,但我需要確保它們在一定時間內超時)

因此,我將其作為實驗,但是如果運行此程序,程序不會終止。 我想知道是否是因為后台線程仍然處於活動狀態? 我該如何關閉?

public class Test {

public static class Task implements Callable<Object> {

    @Override
    public Object call() throws Exception {
        while(true) {}
    }

}

public static void main(String[] args) {
    try {
        Task t = new Task();
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.invokeAll(Arrays.asList(t), 5L, TimeUnit.SECONDS);
        executor.shutdown();
        System.out.println("DONE");
    } 
    catch (InterruptedException e) {
        e.printStackTrace();
    }
}

}

該ExecutorService的不殺死正在運行的線程,並且因為線程是作為非守護創建的,則JVM不會退出。

發生的情況是,當超時到期時,invokeAll()返回的future被取消 ,這意味着在future對象上設置了一個標志,並且如果您嘗試調用future.get() ,則會收到CancellationException 然而,invokeAll()和shutdown()(或shutdownNow())都沒有采取任何措施殺死線程。

請注意,您甚至無法自己殺死線程。 您所能做的就是設置一些特定於應用程序的標志或調用Thread.interrupt() ,但這甚至不能保證線程終止

溫特伯(Winterbe)在執行者的工作方式上有一篇很棒的文章。 這是他的教程的摘錄

因此,基本上執行者總是一直在監聽新任務或可調用對象/可運行對象,而關閉執行者或停止執行者監聽的一種方法是中斷正在執行的任何任務。 一種方法是調用future.get(),該方法在主線程停止時停止,將其掛起,並確保在將資源移交給其他線程之前完全執行當前線程。

您可能擁有更多的線程,並在InterruptedException塊中編寫代碼以正常關閉

這是我編寫和測試的示例代碼:

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ExecutorTest {

    public static void main(String[] args) {

        ExecutorService service = Executors.newWorkStealingPool(10);

        Callable<AccountClass> newInstance = () -> {
            TimeUnit.SECONDS.sleep(3);
            return getAcc(Thread.currentThread().getId());
        };

        // for now only one instance is added to the list
        // List<Callable<AccountClass>> callablesSingleList = Arrays.asList(newInstance);

        // adding multipleCallalbes
        List<Callable<AccountClass>> callablesMultipleList = Arrays.asList(
                () -> {
                    TimeUnit.SECONDS.sleep(3);
                    return getAcc(Thread.currentThread().getId());
                },
                () -> {
                    TimeUnit.SECONDS.sleep(3);
                    return getAcc(Thread.currentThread().getId());
                },
                () -> {
                    TimeUnit.SECONDS.sleep(3);
                    return getAcc(Thread.currentThread().getId());
                });

        try {
            service.invokeAll(callablesMultipleList).stream().map(future -> {
                AccountClass fuClass = null;
                try {
                    fuClass = future.get();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
                return fuClass;
            }).forEach(getValue -> {
                System.out.println("retunred value:" + getValue);
            });
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }

    }

    private static AccountClass getAcc(long itr) {
        // probably call DB for every new thread iterator
        System.out.println("getting the current thread" + itr);
        AccountClass ac = new AccountClass();
        ac.setId(itr);
        ac.setName("vv");
        ac.setRole("admin");
        System.out.println("sending the accnt class:" + ac);
        return ac;
    }
}

更新:

關閉執行程序的另一種方法是使用service.shutDownNow()->,即使程序正在執行中,它也會關閉程序。 您可以使用awaitTermination方法來指定是否感到可能需要幾分鍾才能完成執行,然后可能會關閉服務

import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ExecutorScheduleFixedRate {

    public static void main(String[] args) {

        ScheduledExecutorService service = Executors.newScheduledThreadPool(10);

        Runnable task = () -> {
            getAcc(33);
        };

        service.scheduleWithFixedDelay(task, 10, 5, TimeUnit.SECONDS);

        if (!service.isShutdown()) {
            List<Runnable> list2 = service.shutdownNow();
            System.out.println(list2);
            System.out.println("is shutdonw" + service.isShutdown());
            System.out.println("Do something after the thread execution");
        }

    }

    private static AccountClass getAcc(long itr) {
        // probably call DB for every new thread iterator
        System.out.println("getting the current thread" + itr);
        AccountClass ac = new AccountClass();
        ac.setId(itr);
        ac.setName("vv");
        ac.setRole("admin");
        System.out.println("sending the accnt class:" + ac);
        return ac;
    }

}

暫無
暫無

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

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