Java Concurrency 11--Application of Callable and Future



  The Callable interface is similar to Runnable, both are designed for classes whose instances may be executed by another thread. But Runnable doesn't return results and cannot throw checked exceptions. Callable can return a result, and this return value can be obtained by Future, that is, Future can obtain the return value of asynchronously executed tasks. Let's look at a simple example:

public class CallableAndFuture {

    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newSingleThreadExecutor();// 创建一个线程即可
        Future<String> future = threadPool.submit(
                new Callable<String>() {

                    @Override
                    public String call() throws Exception {
                        Thread.sleep(2000);
                        return "hello";
                    }
                }   
            );
        System.out.println("等待结果:");
        try {
            System.out.println("拿到结果:" + future.get());
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

  Use the concurrent library to create a thread. As mentioned in the previous blog post, if you call the execute method, you need to pass in a Runnable. Now I call the submit method, you can pass in a Callable, and then rewrite the call method to return a us The required data, and then we use Future to receive the returned data, which can be obtained through the future.get() method.
  So the question is, isn't it more troublesome to do this? I might as well just call a method and return a value, I get it right away, why is it so troublesome! It makes sense, but the combination of Callable and Future is not useful here. Suppose there is a time-consuming return value that needs to be calculated, and the return value is not needed immediately, then you can use this combination, use another thread to calculate the return value, and the current thread can do other things before using the return value Operation, wait until the return value is needed, and then get it through Future. Isn't this a good design?
  The official introduction to Future is as follows:

Future represents the result of an asynchronous computation. It provides methods to check whether the calculation is complete, to wait for the completion of the calculation, and get the result of the calculation. After the calculation is completed, only the get method can be used to obtain the result, if necessary, this method can be blocked until the calculation is completed. Cancellation is performed by the cancel method. Additional methods are provided to determine whether a task completed normally or was canceled. Once a calculation is complete, it cannot be cancelled.

  Looking at the JDK documentation, there is a cancel method that is used to cancel the task, which means that we can cancel it manually, which is more flexible. As mentioned above, when the amount of calculation is relatively large, if under different circumstances, whether The need to calculate is uncertain. If xxx, let it calculate the result. If xxx, there is no need to calculate, then we can use this Future flexibly. In addition, before canceling, we can also judge whether it has been executed. There are related methods.
  
  The above is the case of a single thread execution. Now if there are multiple threads executing and there are multiple return values, what should we do? In this case, we have to use CompletionService<T>the interface, look at the specific code:

public class CallableAndFuture {

    public static void main(String[] args) {

        ExecutorService threadPool = Executors.newCachedThreadPool();//定义一个缓存线程池
        CompletionService<Integer> completionService = 
                new ExecutorCompletionService<Integer>(threadPool); //将线程池扔进去
        for(int i = 1; i <= 5; i ++) {
            final int seq = i;
            completionService.submit( //用里面装的线程去执行这些任务,每个线程都会返回一个数据
                    new Callable<Integer> () {

                        @Override
                        public Integer call() throws Exception {
                            Thread.sleep(new Random().nextInt(5000));
                            return seq;
                        }

                    }
                );
        }
        for(int i = 0; i < 5; i ++) { //执行完了后,再取出来
            try {
                System.out.print(completionService.take().get() + " ");
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } 
        }
    }   
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

  The difference between this method and the above method is that when there is a single thread above, the ExecutorService object is used to execute submit. When there are multiple threads, the thread pool is thrown into CompletionService<T>it, and then submit is executed. Finally, we are calling take() And get() method to get the result. It is more convenient to use. Let's take a look at the introduction of the JDK documentation:

  A service that separates producing new asynchronous tasks from consuming the results of completed tasks. The task that the producer submits to perform. Consumers take completed tasks and process their results in the order in which they were completed.
  Typically, the CompletionService relies on a separate Executor to actually execute the tasks, in this case the CompletionService just manages an internal completion queue.

  The official introduction is consistent with the program written above. First, take gets the completed tasks, and then get gets each task. And process these tasks in the order in which they are completed, that is, when the thread is just executed, whichever thread executes first will get the result of the thread's execution first.
  

  Related reading: http://blog.csdn.net/column/details/bingfa.html




  The Callable interface is similar to Runnable, both are designed for classes whose instances may be executed by another thread. But Runnable doesn't return results and cannot throw checked exceptions. Callable can return a result, and this return value can be obtained by Future, that is, Future can obtain the return value of asynchronously executed tasks. Let's look at a simple example:

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326852356&siteId=291194637