多线程之 Future 学习

/ FutureJava / 没有评论 / 1539浏览

Future Start

学习 Future 之前先简单的学习一下 CallableRunnable

Callable 和 Runnable

Java 多线程实现方式主要有四种:

  1. 继承 Thread
  2. 实现 Runnable 接口
  3. 实现 Callable 接口通过 FutureTask 包装器来创建 Thread 线程、
  4. 使用 ExecutorService、Callable、Future 实现有返回结果的多线程。

Runnable

代码

package java.lang;

@FunctionalInterface
public interface Runnable {
    void run();
}
    public class MyTask implements Runnable{
        CountDownLatch latch;
        public MyTask(CountDownLatch latch){
            this.latch = latch;
        }
        public MyTask(){
            this.latch = null;
        }
        @Override
        public void run(){
            try{
                System.out.println("Starting my task");
                Thread.sleep(1000);
                System.out.println("Done my task");
            } catch (InterruptedException e){
                System.out.println(e.fillInStackTrace());
            } finally {
                if(this.latch != null){
                    latch.countDown();
                }
            }
        }
    }
    @Test
    public void testRunnable()throws InterruptedException{
        Thread thread = new Thread(new MyTask());
        thread.start();
        thread.join();
    }
    public void testRunnable1()throws InterruptedException{
        ExecutorService service = Executors.newFixedThreadPool(1);
        service.execute(new MyTask());
        service.shutdown();
        /**主线程等待子线程执行结束再结束**/
        try {
            service.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
        } catch (InterruptedException e) {
            System.out.println(e.fillInStackTrace());
        }
    }
    /**使用CountDownLatch使主进程等待子进程**/
        @Test
    public void testRunnable2()throws InterruptedException{
        CountDownLatch latch = new CountDownLatch(1);
        ExecutorService service = Executors.newFixedThreadPool(1);
        service.execute(new MyTask(latch));

        try {
            System.out.println("Waiting one sub thread ...");
            latch.await();
            System.out.println("Sub thread all donne");
            System.out.println("Continuing main thread");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

Callable

接口定义

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}
    public class MyCallable implements Callable<String>{
        private String context;
        public MyCallable(String context){
            this.context = context;
        }
        @Override
        public String call(){
           try{
               Thread.sleep(1000);
               return this.context + " append something";
           } catch (InterruptedException e){
               e.printStackTrace();
           }
           return this.context;
        }
    }

    @Test
    public void testCallable()throws ExecutionException,InterruptedException{
        Callable<String> mCallable = new MyCallable("Wether is good.");
        FutureTask<String> task = new FutureTask<>(mCallable);
        Thread thread = new Thread(task);
        thread.start();
        //调用get方法阻塞主线程
        String result = task.get();
        System.out.println(result);
    }
    @Test
    public void testCallable2()throws ExecutionException,InterruptedException{
        ExecutorService service = Executors.newFixedThreadPool(1);
        Callable<String> mCallable = new MyCallable("Wether is good.");
        FutureTask<String> task = new FutureTask<>(mCallable);
        service.execute(task);
        //调用get方法阻塞主线程
        String result = task.get();
        System.out.println(result);
    }
    @Test
    public void testCallable3()throws ExecutionException,InterruptedException{
        ExecutorService service = Executors.newFixedThreadPool(1);
        Callable<String> mCallable = new MyCallable("Wether is good.");
        Future<String> future = service.submit(mCallable);
        //调用get方法阻塞主线程
        String result = future.get();
        System.out.println(result);
    }

FutureTask

代码

public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}
public class FutureTask<V> implements RunnableFuture<V> {
    ...
}

Future

如上面的介绍,Future 的两种典型用法,这两种用法的主要不同点就是线程池使用 execute、submit 执行的区别。但是 Future 有个明显的缺点,get 方法会阻塞当前线程,也就下面的两种用法只能串行执行。这和我们预想的不太一样,这也是下面要学习的 CompletableFuture 所要解决的问题。

    @Test
    public void testFuture()throws ExecutionException,InterruptedException{
        //用法一
        ExecutorService service = Executors.newFixedThreadPool(2);
        Callable<String> mCallable = new MyCallable("Wether is good.");
        FutureTask<String> task = new FutureTask<>(mCallable);
        service.execute(task);
        //调用get方法阻塞主线程
        String result = task.get();
        System.out.println(result);

        //用法二
        Callable<String> mCallable1 = new MyCallable("Wether is good.");
        Future<String> future1 = service.submit(mCallable);
        //调用get方法阻塞主线程
        String result1 = future1.get();
        System.out.println(result1);
    }