使用线程时程序执行成功但程序没有结束

The execution of the program doesn't end though the program executed successfully when using threads

我正在探索java.util.concurrent.* 计算平方并使用 Thread.sleep(5000) 等待,程序按预期工作,但永远不会终止。

eclipse中的红色方块是"ON",我们通常用它来终止程序。

能否请您帮助理解为什么程序在完成时没有终止?



    public static void main(String[] args) throws InterruptedException, ExecutionException {
        // TODO Auto-generated method stub
        try {
        SquareCalculator sqC = new SquareCalculator();
        sqC.display(1);
        Future<Integer> result = sqC.calculate(5);

        while(!result.isDone())
        {
            System.out.println("Waiting for the calculation");
            Thread.sleep(1000);
            //result.cancel(true);
        }
        Integer square = result.get();
        System.out.println(square);
        }catch(Exception e)
        {
            e.printStackTrace();
            System.out.println("Calclulation was interrupted");
        }
    }

public class SquareCalculator {

    private ExecutorService ex = Executors.newSingleThreadExecutor();

    public void display(int i) {
        // TODO Auto-generated method stub
        System.out.println(i);
    }

    public Future<Integer> calculate(Integer inp)
    {
        try {
            System.out.println("Before sending request");
        Future<Integer> res = ex.submit(()->{

            Thread.sleep(5000);
            return inp*inp;
        });
        System.out.println("Request sent to caluclate and waiting for the result");
        return res;
        }catch(Exception e)
        {
            System.out.println("calculation was interrupted");
            return null;
        }
        //return ex.submit(()->squareing(inp));

    }

}

输出

1
Before sending request
Request sent to caluclate and waiting for the result
Waiting for the calculation
Waiting for the calculation
Waiting for the calculation
Waiting for the calculation
Waiting for the calculation
25

如果要关闭虚拟机,请调用System.exit()。是的,VM 也可以在不调用该方法的情况下自动关闭;如果所有仍然 'live' 的线程都有 'daemon' 标志(线程 class 有一个 .setDaemon 方法用于此目的),它就会这样做,但这是糟糕的代码风格。如果重点是关机,那就关机(用System.exit)。

具体在这里,Executors.newSingleThreadExecutor()创建的线程;未标记为守护线程。您可以通过为调用提供一个线程创建者来解决这个问题。

但是,真的,不要。使用 System.exit.

您需要重构您的代码和 return 对象而不是 Future。完成后你还应该关闭执行器。


import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class SquareCalculator {

    private ExecutorService ex = Executors.newSingleThreadExecutor();

    public void display(int i) {
        // TODO Auto-generated method stub
        System.out.println(i);
    }

    public Integer calculate(Integer inp) {
        Integer result;
        try {
            System.out.println("Before sending request");
            Future<Integer> res = ex.submit(() -> {
                Thread.sleep(5000);
                return inp * inp;
            });
            System.out.println("Request sent to caluclate and waiting for the result");
            result = res.get();
            ex.shutdown();
            return result;
        } catch (Exception e) {
            System.out.println("calculation was interrupted");
            return null;
        }
        //return ex.submit(()->squareing(inp));

    }

    public static void main(String[] args) throws InterruptedException, 
        ExecutionException {
        // TODO Auto-generated method stub
        try {
            SquareCalculator sqC = new SquareCalculator();
            sqC.display(1);
            Integer result = sqC.calculate(5);
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Calclulation was interrupted");
        }
    }
}

我宁愿在计算器之外创建一个执行器 class 并将其传递给构造函数。

这样应用程序就可以控制 ExecutorService 并在必要时将其关闭。

此外,如果您创建一个以上的计算器实例,所有实例都使用相同的执行器服务,因此您可以控制有多少实例可以运行 并行。

calculate 方法中的阻塞有效,但违背了使用另一个线程进行异步计算的目的。

    public static void main(String[] args) {
        // The executor is created by the application and then 
        // passed to the calculator
        ExecutorService executor = Executors.newCachedThreadPool();
        SquareCalculator calculator = new SquareCalculator(executor);

        // calculate does not block
        Future<Integer> calculate = calculator.calculate(12);

        try {
            while(true) {
                try {
                    // wait a limited amount of time for the computation to complete   
                    Integer result = calculate.get(1, TimeUnit.SECONDS);
                    System.out.println(result);
                    if(calculate.isDone()) {
                        // If the computation was either complete or cancelled just quit 
                        break;
                    }
                } catch (TimeoutException e) {
                    // We expect timeouts so we don't quit the loop for them
                    System.out.println("Waiting for result");
                }
            }
        } catch (InterruptedException | ExecutionException e) {
            // If there was an error or the computation was interrupted just quit.
            e.printStackTrace();
        }
        // Shut down the executor so we do not leak pools. 
        executor.shutdown();
    }
    public class SquareCalculator {

        private ExecutorService ex;

        public SquareCalculator(ExecutorService ex) {
            super();
            this.ex = ex;
        }

        public void display(int i) {
            System.out.println(i);
        }

        public Future<Integer> calculate(Integer inp) {
            try {
                System.out.println("Before sending request");
                Future<Integer> res = ex.submit(() -> {

                    Thread.sleep(5000);
                    return inp * inp;
                });
                System.out.println("Request sent to caluclate and waiting for the result");
                return res;
            } catch (Exception e) {
                System.out.println("calculation was interrupted");
                return null;
            }
        }
    }