尽管在使用线程时成功执行了程序,但程序的执行并未结束

时间:2019-05-13 23:40:56

标签: java multithreading java.util.concurrent

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

日食中的红色正方形是“ 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

3 个答案:

答案 0 :(得分:1)

您需要重构代码并返回该对象而不是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");
        }
    }
}

答案 1 :(得分:0)

我宁愿在Calculator类之外创建执行程序,并将其传递给构造函数。

通过这种方式,应用程序可以控制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;
            }
        }
    }

答案 2 :(得分:-1)

如果要关闭VM,请致电System.exit()。是的,VM也可以自动关闭而无需调用该方法。如果所有仍处于“活动”状态的线程都具有“ daemon”标志(为此Thread类具有.setDaemon方法),则会执行此操作,但这是错误的代码样式。如果要关闭,请关闭(使用System.exit)。

具体来说,这里是Executors.newSingleThreadExecutor();创建的线程。没有标记为守护程序线程。您可以通过为调用提供线程创建器来解决此问题。

但是,实际上不是。使用System.exit