zoukankan      html  css  js  c++  java
  • Java线程实现的第三种方式Callable方式与结合Future获取返回值

      多线程的实现方式有实现Runnable接口和继承Thread类(实际上Thread类也实现了Runnable接口),但是Runnable接口的方式有两个弊端,第一个是不能获取返回结果,第二个是不能抛出exception。但是Callable接口很好的解决了上面的问题。下面介绍Callable接口的使用方法。

      

    0.我们先看JDKAPI对callable接口的解释:

    public interface Callable<V>
    
    

      返回结果并且可能抛出异常的任务。实现者定义了一个不带任何参数的叫做 call 的方法。

      Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常。

      Executors 类包含一些从其他普通形式转换成 Callable 类的实用方法。

    方法解释:

    call

    V call()
           throws Exception
    计算结果,如果无法计算结果,则抛出一个异常。
    返回:
    计算的结果
    抛出:
    Exception - 如果无法计算结果

    1.第一个实现Callable接口开启线程的用法:(不接受返回值,只是开启线程执行任务)

    package threadTest;
    
    import java.util.concurrent.Callable;
    import java.util.concurrent.FutureTask;
    
    /**
     * 实现callable接口,实现Callable接口
     * 
     *
     */
    public class MyCallable implements Callable<String> {
    
        /**
         * 实现call方法,接口中抛出异常。因为子类不可以比父类干更多的坏事,所以子类可以不抛出异常
         */
        @Override
        public String call() {
            System.out.println(Thread.currentThread().getName() + "   执行callable的call方法");
            return "result";
        }
    
        public static void main(String[] args) {
            // 1.创建callable对象
            Callable<String> myCallable = new MyCallable();
            // 2.由上面的callable对象创建一个FutureTask对象
            FutureTask<String> oneTask = new FutureTask<String>(myCallable);
            // 3.由FutureTask创建一个Thread对象
            Thread t = new Thread(oneTask);
            // 4.开启线程
            t.start();
        }
    
    }

     结果:

    Thread-0   执行callable的call方法

    解释:

      (1)Callable接口不用解释了,就是一个类似于Runnable接口的接口,只有一个call方法,此方法有返回值,可以抛出异常。

      (2)Futuretask类查看:实现了RunnableFuture接口,RunnableFuture接口继承于Runnable接口和Future接口:所以Futuretask是Runnable的对象(子类的对象也是父类的对象)

    public class FutureTask<V> implements RunnableFuture<V> {

    查看此类的构造方法:初始化成员变量callable

        public FutureTask(Callable<V> callable) {
            if (callable == null)
                throw new NullPointerException();
            this.callable = callable;
            this.state = NEW;       // ensure visibility of callable
        }

    查看此类的run方法:(调用Callable的call()方法)

        public void run() {
            if (state != NEW ||
                !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                             null, Thread.currentThread()))
                return;
            try {
                Callable<V> c = callable;
                if (c != null && state == NEW) {
                    V result;
                    boolean ran;
                    try {
                        result = c.call();
                        ran = true;
                    } catch (Throwable ex) {
                        result = null;
                        ran = false;
                        setException(ex);
                    }
                    if (ran)
                        set(result);
                }
            } finally {
                // runner must be non-null until state is settled to
                // prevent concurrent calls to run()
                runner = null;
                // state must be re-read after nulling runner to prevent
                // leaked interrupts
                int s = state;
                if (s >= INTERRUPTING)
                    handlePossibleCancellationInterrupt(s);
            }
        }

        JDKAPI对此类的解释:

        

          

      (3)RunnableFuture接口:

    public interface RunnableFuture<V> extends Runnable, Future<V> {
        void run();
    }

      (4)Runnable接口不用解释了,Future接口的解释如下:===也就是Future用于获取Callable执行的返回结果

    package java.util.concurrent;
    public interface Future<V> {
    
        boolean cancel(boolean mayInterruptIfRunning);
    
        boolean isCancelled();
    
        boolean isDone();
    
        V get() throws InterruptedException, ExecutionException;
    
        V get(long timeout, TimeUnit unit)
            throws InterruptedException, ExecutionException, TimeoutException;
    }

       JDKAPI的解释:

    public interface Future<V>

      Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,如有必要,计算完成前可以阻塞此方法。取消则由 cancel 方法来执行。还提供了其他方法,以确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算。如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明 Future<?> 形式类型、并返回 null 作为底层任务的结果。

    用法示例(注意,下列各类都是构造好的。)

     interface ArchiveSearcher { String search(String target); }
     class App {
       ExecutorService executor = ...
       ArchiveSearcher searcher = ...
       void showSearch(final String target)
           throws InterruptedException {
         Future<String> future
           = executor.submit(new Callable<String>() {
             public String call() {
                 return searcher.search(target);
             }});
         displayOtherThings(); // do other things while searching
         try {
           displayText(future.get()); // use future
         } catch (ExecutionException ex) { cleanup(); return; }
       }
     }
     

    FutureTask 类是 Future 的一个实现,Future 可实现 Runnable,所以可通过 Executor 来执行。例如,可用下列内容替换上面带有 submit 的构造:

         FutureTask<String> future =
           new FutureTask<String>(new Callable<String>() {
             public String call() {
               return searcher.search(target);
           }});
         executor.execute(future);

       (5)Thread类可以接受一个Runnable接口,上面代码FutureTask实现了RunnableFuture接口,RunnableFuture接口继承于Runnable接口,所以可以接受FutureTask对象。

     2.使用ExecutorService、Callable、Future实现有返回结果的线程

     1.单线程的获取返回结果:

    package threadTest;
    
    import java.util.ArrayList;
    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.Future;
    
    /**
     * 实现callable接口,实现Callable接口
     * 
     *
     */
    public class MyCallable implements Callable<String> {
    
        /**
         * 实现call方法,接口中抛出异常。因为子类不可以比父类干更多的坏事,所以子类可以不抛出异常
         */
        @Override
        public String call() {
            System.out.println(Thread.currentThread().getName() + "   执行callable的call方法");
            return "result";
        }
    
        public static void main(String[] args) {
            test1();
        }
    
        /**
         * 单个线程
         */
        public static void test1() {
            // 1.创建固定大小的线程池
            ExecutorService es = Executors.newFixedThreadPool(1);
            // 2.提交线程任务,用Future接口接受返回的实现类
            Future<String> future = es.submit(new MyCallable());
            // 3.关闭线程池
            es.shutdown();
            // 4.调用future.get()获取callable执行完成的返回结果
            String result;
            try {
                result = future.get();
                System.out.println(Thread.currentThread().getName() + "	" + result);
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
    }

     结果:

    pool-1-thread-1 执行callable的call方法
    main result

    2.多个线程的执行返回结果:

    package threadTest;
    
    import java.util.ArrayList;
    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.Future;
    
    /**
     * 实现callable接口,实现Callable接口
     * 
     *
     */
    public class MyCallable implements Callable<String> {
    
        /**
         * 实现call方法,接口中抛出异常。因为子类不可以比父类干更多的坏事,所以子类可以不抛出异常
         */
        @Override
        public String call() {
            System.out.println(Thread.currentThread().getName() + "   执行callable的call方法");
            return "result";
        }
    
        public static void main(String[] args) {
            test2();
        }
    /**
         * 多个线程
         */
        public static void test2() {
            // 1.创建固定大小的线程池(5个)
            int threadNum = 5;
            ExecutorService es = Executors.newFixedThreadPool(threadNum);
            // 2.提交线程任务,用Future接口接受返回的实现类
            List<Future<String>> futures = new ArrayList<Future<String>>(threadNum);
            for (int i = 0; i < threadNum; i++) {
                Future<String> future = es.submit(new MyCallable());
                futures.add(future);
            }
            // 3.关闭线程池
            es.shutdown();
            // 4.调用future.get()获取callable执行完成的返回结果
            for (Future<String> future : futures) {
                try {
                    String result = future.get();
                    System.out.println(Thread.currentThread().getName() + "	" + result);
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }
    
    }

     结果:

    pool-1-thread-1 执行callable的call方法
    pool-1-thread-2 执行callable的call方法
    pool-1-thread-4 执行callable的call方法
    pool-1-thread-3 执行callable的call方法
    main result
    pool-1-thread-5 执行callable的call方法
    main result
    main result
    main result
    main result

    总结:

       ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。

    线程池的使用参考:https://www.cnblogs.com/qlqwjy/p/9470414.html

  • 相关阅读:
    用sql合并列,两句话合为一句
    微信公众平台中添加qq在线聊天代码
    我被7岁4岁的小姐妹狠狠教训了一番
    Yahoo News Digest(雅虎新闻摘要)APP的推出,未来的seo界又要受伤了
    新浪微博@别人字母不分大小写(微博昵称不分大小写)
    最近打算体验一下discuz,有不错的结构化数据插件
    使用css3来实现边框圆角效果
    用WP_Query自定义WordPress 主循环
    关闭火车头dedecms发布模块自动关键词,解决火车头发布dedecms文章关键词过多问题
    dedecms发布文章时多个Tag间分割逗号自动变成英文逗号
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/9657981.html
Copyright © 2011-2022 走看看