• Java线程—-Runnable和Callable的区别和联系


    Java 提供了三种创建线程的方法


    1.继承Thread接口

     1 public class Thread2Thread {
     2     public static void main(String[] args) {
     3         new MyThread1().start();
     4         new Thread(new MyThread1(), "线程2").start();
     5     }
     6 }
     7 
     8 /**
     9  * 通过继承Thread类
    10  */
    11 class MyThread1 extends Thread {
    12     /**
    13      * 重写run方法
    14      */
    15     @Override
    16     public void run() {
    17         // TODO Auto-generated method stub
    18         super.run();
    19     }
    20 }
    通过继承Thread类

    2.实现Runnable接口

     1 package com.testthread.demo4;
     2 
     3 import java.util.concurrent.ExecutorService;
     4 
     5 import static java.util.concurrent.Executors.*;
     6 
     7 public class Thread2Runnable {
     8 
     9     public static void main(String[] args) {
    10 
    11         //case1:通过实现Runnable接口,来实现run方法的具体逻辑
    12         new Thread(new MyThread2(), "线程1").start();
    13         //case2:匿名内部类
    14         new Thread(new Runnable() {
    15             @Override
    16             public void run() {
    17                 // TODO Auto-generated method stub
    18 
    19             }
    20         }, "线程2").start();
    21 
    22         //其实case1和case2的本质是一样的
    23         
    24         //case3:作为线程任务提交给线程池,通过线程池维护的工作者线程来执行。
    25         ExecutorService executor = newCachedThreadPool();
    26         MyThread2 myThread2 = new MyThread2();
    27         executor.execute(myThread2);
    28         executor.shutdown();
    29     }
    30 }
    31 
    32 /**
    33  * 实现Runnable接口的线程类
    34  */
    35 class MyThread2 implements Runnable {
    36 
    37     /**
    38      * 重写run方法
    39      */
    40     @Override
    41     public void run() {
    42         // TODO Auto-generated method stub
    43     }
    44 }
    实现Runnable接口

    3.通过Callable和Future创建线程

     1 import java.util.concurrent.Callable;
     2 import java.util.concurrent.FutureTask;
     3 
     4 public class Thread2Callable {
     5     public static void main(String[] args) {
     6         //创建 Callable 实现类的实例
     7         MyCallable myCallable = new MyCallable();
     8         //使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值
     9         FutureTask<String> futureTask = new FutureTask<String>(myCallable);
    10         String res = null;
    11         try {
    12             //使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程
    13             //没这句,下句代码获取不到结果,会一直等待执行结果
    14             new Thread(futureTask,"线程1").start();
    15             //调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值
    16             res = futureTask.get();
    17         } catch (Exception e) {
    18             e.printStackTrace();
    19         }
    20         System.out.println(res);
    21     }
    22 }
    23 /**
    24  * 创建 Callable 接口的实现类,并实现 call() 方法
    25  */
    26 class MyCallable implements Callable<String> {
    27 
    28     /**
    29      * 该 call() 方法将作为线程执行体,并且有返回值
    30      */
    31     @Override
    32     public String call() throws Exception {
    33         return "success";
    34     }
    35 }
    通过Callable和Future创建线程

    Runnable和Callable的区别和联系

    接口定义

      Runnable  

    其中Runnable应该是我们最熟悉的接口,它只有一个run()函数,用于将耗时操作写在其中,该函数没有返回值。然后使用某个线程去执行该runnable即可实现多线程,Thread类在调用start()函数后就是执行的是Runnable的run()函数。

    Runnable的声明如下 :

    1 public interface Runnable {
    2     /*
    3      * @see     java.lang.Thread#run()
    4      */
    5     public abstract void run();
    6 }
    Runnable

      #Callable

    Callable与Runnable的功能大致相似,Callable中有一个call()函数,但是call()函数有返回值,而Runnable的run()函数不能将结果返回给客户程序。

    Callable的声明如下 :

    1 public interface Callable<V> {
    2     /**
    3      * Computes a result, or throws an exception if unable to do so.
    4      *
    5      * @return computed result
    6      * @throws Exception if unable to compute a result
    7      */
    8     V call() throws Exception;
    9 }
    View Code

      #Future

    Executor就是Runnable和Callable的调度容器,Future就是对于具体的Runnable或者Callable任务的执行结果进行
    取消、查询是否完成、获取结果、设置结果操作。get方法会阻塞,直到任务返回结果(Future简介)。

    Future声明如下 :

     1 public interface Future<V> {
     2  
     3     /**
     4      * Attempts to cancel execution of this task.  This attempt will
     5      * fail if the task has already completed, has already been cancelled,
     6      * or could not be cancelled for some other reason. If successful,
     7      * and this task has not started when <tt>cancel</tt> is called,
     8      * this task should never run.  If the task has already started,
     9      * then the <tt>mayInterruptIfRunning</tt> parameter determines
    10      * whether the thread executing this task should be interrupted in
    11      * an attempt to stop the task.
    12      */
    13     boolean cancel(boolean mayInterruptIfRunning);
    14  
    15     /**
    16      * Returns <tt>true</tt> if this task was cancelled before it completed
    17      * normally.
    18      */
    19     boolean isCancelled();
    20  
    21     /**
    22      * Returns <tt>true</tt> if this task completed.
    23      *
    24      */
    25     boolean isDone();
    26  
    27     /**
    28      * Waits if necessary for the computation to complete, and then
    29      * retrieves its result.
    30      *
    31      * @return the computed result
    32      */
    33     V get() throws InterruptedException, ExecutionException;
    34  
    35     /**
    36      * Waits if necessary for at most the given time for the computation
    37      * to complete, and then retrieves its result, if available.
    38      *
    39      * @param timeout the maximum time to wait
    40      * @param unit the time unit of the timeout argument
    41      * @return the computed result
    42      */
    43     V get(long timeout, TimeUnit unit)
    44         throws InterruptedException, ExecutionException, TimeoutException;
    45 }
    Future

    #FutureTask(很有用)

      FutureTask是一个RunnableFuture<V>  

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

     RunnableFuture实现了Runnbale又实现了Futrue<V>这两个接口

    1 public interface RunnableFuture<V> extends Runnable, Future<V> {
    2     /**
    3      * Sets this Future to the result of its computation
    4      * unless it has been cancelled.
    5      */
    6     void run();
    7 }
    RunnableFuture

    另外FutureTaslk还可以包装Runnable和Callable<V>, 由构造函数注入依赖。

     1     public FutureTask(Callable<V> callable) {
     2         if (callable == null)
     3             throw new NullPointerException();
     4         this.callable = callable;
     5         this.state = NEW;       // ensure visibility of callable
     6     }
     7  
     8     public FutureTask(Runnable runnable, V result) {
     9         this.callable = Executors.callable(runnable, result);
    10         this.state = NEW;       // ensure visibility of callable
    11     }
    FutureTask(callable)

    上面代码块可以看出:Runnable注入会被Executors.callable()函数转换为Callable类型,即FutureTask最终都是执行Callable类型的任务。

    该适配函数的实现如下 :

    1     public static <T> Callable<T> callable(Runnable task, T result) {
    2         if (task == null)
    3             throw new NullPointerException();
    4         return new RunnableAdapter<T>(task, result);
    5     }
    callable

    RunnableAdapter适配器

     1     /**
     2      * A callable that runs given task and returns given result
     3      */
     4     static final class RunnableAdapter<T> implements Callable<T> {
     5         final Runnable task;
     6         final T result;
     7         RunnableAdapter(Runnable task, T result) {
     8             this.task = task;
     9             this.result = result;
    10         }
    11         public T call() {
    12             task.run();
    13             return result;
    14         }
    15     }
    RunnableAdapter
    FutureTask实现Runnable,所以能通过Thread包装执行,
    
    FutureTask实现Runnable,所以能通过提交给ExcecuteService来执行
    
    注:ExecuteService:创建线程池实例对象,其中有submit(Runnable)、submit(Callable)方法
    
    ExecturService:https://blog.csdn.net/suifeng3051/article/details/49443835
    
    还可以直接通过get()函数获取执行结果,该函数会阻塞,直到结果返回。
    
    因此FutureTask是Future也是Runnable,又是包装了的Callable( 如果是Runnable最终也会被转换为Callable )。

    相同点

    1 都是接口
    2 都可以编写多线程程序
    3 都采用Thread.start()启动线程

     不同点

    1  Callable规定的方法是call(),而Runnable规定的方法是run(). 
    2  Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。  
    3   call()方法可抛出异常,而run()方法是不能抛出异常的。--run()方法异常只能在内部消化,不能往上继续抛
    4   运行Callable任务可拿到一个Future对象, Future表示异步计算的结果。 
    5   它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。 
    6   通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。 
    7  Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。 
    注:Callalbe接口支持返回执行结果,需要调用FutureTask.get()得到,此方法会阻塞主进程的继续往下执行,如果不调用不会阻塞。

     示例:

     1 package com.xzf.callable;
     2  
     3 import java.util.concurrent.Callable;
     4 import java.util.concurrent.ExecutorService;
     5 import java.util.concurrent.Executors;
     6 import java.util.concurrent.Future;
     7 import java.util.concurrent.FutureTask;
     8  
     9 public class RunnableFutureTask {
    10     static ExecutorService executorService = Executors.newSingleThreadExecutor();    //创建一个单线程执行器
    11     public static void main(String[] args) {
    12         runnableDemo();    
    13         futureDemo();
    14     }
    15     /**
    16      * new Thread(Runnable arg0).start(); 用Thread()方法开启一个新线程
    17      * runnable, 无返回值
    18      */
    19     static void runnableDemo() {
    20         new Thread(new Runnable() {                
    21             public void run() {
    22                 System.out.println("runnable demo:" + fibc(20));    //有值
    23             }
    24             
    25         }).start();
    26     }
    27     /**
    28      * Runnable实现的是void run()方法,无返回值
    29      * Callable实现的是 V call()方法,并且可以返回执行结果
    30      * Runnable可以提交给Thread,在包装下直接启动一个线程来执行
    31      * Callable一般都是提交给ExecuteService来执行
    32      */ 
    33      
    34     static void futureDemo() {
    35         try {
    36             Future<?> result1 = executorService.submit(new Runnable() {
    37                 public void run() {
    38                     fibc(20);
    39                 }
    40             });
    41             System.out.println("future result from runnable:"+result1.get());    //run()无返回值所以为空,result1.get()方法会阻塞
    42             Future<Integer> result2 = executorService.submit(new Callable<Integer>()     {
    43                 public Integer call() throws Exception {
    44                     return fibc(20);    
    45                 }
    46             });
    47             System.out.println("future result from callable:"+result2.get());    //call()有返回值,result2.get()方法会阻塞
    48             FutureTask<Integer> result3 = new FutureTask<Integer>(new Callable<Integer>() {
    49                 public Integer call() throws Exception {
    50                     return fibc(20);
    51                 }
    52             });
    53             executorService.submit(result3);    
    54             System.out.println("future result from FutureTask:" + result3.get());    //call()有返回值,result3.get()方法会阻塞
    55             
    56             /*因为FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行*/
    57             FutureTask<Integer> result4 = new FutureTask<Integer>(new Runnable() {
    58                 public void run() {
    59                     fibc(20);
    60                 }
    61             },fibc(20));    
    62             executorService.submit(result4);
    63             System.out.println("future result from executeService FutureTask :" + result4.get());    //call()有返回值,result3.get()方法会阻塞
    64             //这里解释一下什么FutureTask实现了Runnable结果不为null,这就用到FutureTask对Runnable的包装,所以Runnable注入会被Executors.callable()函数转换成Callable类型
    65  
    66             FutureTask<Integer> result5 = new FutureTask<Integer>(new Runnable() {
    67                 public void run() {
    68                     fibc(20);
    69                 }
    70             },fibc(20));
    71             new Thread(result5).start();
    72             System.out.println("future result from Thread FutureTask :" + result5.get());    //call()有返回值,result5.get()方法会阻塞
    73             
    74         } catch (Exception e) {
    75             e.printStackTrace();
    76         }finally {
    77             executorService.shutdown();
    78         }
    79     }
    80     static int fibc(int num) {
    81         if (num==0) {
    82             return 0;
    83         }
    84         if (num==1) {
    85             return 1;
    86         }
    87         return fibc(num-1) + fibc(num-2);
    88     }
    89 }
    示例1

    运行结果:

    1 runnable demo:6765
    2 future result from runnable:null
    3 future result from callable:6765
    4 future result from FutureTask:6765
    5 future result from executeService FutureTask :6765
    6 future result from Thread FutureTask :6765
    运行结果1
     1 package com.testthread.test;
     2 
     3 import java.util.concurrent.*;
     4 import java.util.Date;
     5 import java.util.List;
     6 import java.util.ArrayList;
     7 
     8 public class Test implements Callable<Object> {
     9     private String taskNum;
    10 
    11     Test(String taskNum) {
    12         this.taskNum = taskNum;
    13     }
    14 
    15     public static void main(String[] args) {
    16         System.out.println("----程序开始运行----");
    17         Date date1 = new Date();
    18         int taskSize = 5; // 创建一个线程池
    19         ExecutorService pool = Executors.newFixedThreadPool(taskSize); // 创建多个有返回值的任务
    20         List<Future> list = new ArrayList<Future>();
    21         try {
    22             for (int i = 0; i < taskSize; i++) {
    23                 Callable c = new Test(i + " "); // 执行任务并获取Future对象
    24                 Future f = pool.submit(c);
    25                 list.add(f);
    26             }
    27             // 获取所有并发任务的运行结果
    28             for (Future f : list) {
    29                 // 从Future对象上获取任务的返回值,并输出到控制台
    30                 System.out.println(">>>" + f.get().toString());
    31             }
    32         } catch (InterruptedException e) {
    33             e.printStackTrace();
    34         } catch (ExecutionException e) {
    35             e.printStackTrace();
    36         } finally {// 关闭线程池
    37             pool.shutdown();
    38         }
    39         Date date2 = new Date();
    40         System.out.println("----程序结束运行----,程序运行时间【" + (date2.getTime() - date1.getTime()) + "毫秒】");
    41     }
    42 
    43     @Override
    44     public Object call() throws Exception {
    45         System.out.println(">>>" + taskNum + "任务启动");
    46         Date dateTmp1 = new Date();
    47         Thread.sleep(1000);
    48         Date dateTmp2 = new Date();
    49         long time = dateTmp2.getTime() - dateTmp1.getTime();
    50         System.out.println(">>>" + taskNum + "任务终止");
    51         return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】";
    52     }
    53 }
    示例2
     1 ----程序开始运行----
     2 >>>1 任务启动
     3 >>>0 任务启动
     4 >>>3 任务启动
     5 >>>2 任务启动
     6 >>>4 任务启动
     7 >>>1 任务终止
     8 >>>3 任务终止
     9 >>>0 任务终止
    10 >>>0 任务返回运行结果,当前任务时间【1029毫秒】
    11 >>>2 任务终止
    12 >>>1 任务返回运行结果,当前任务时间【1029毫秒】
    13 >>>2 任务返回运行结果,当前任务时间【1030毫秒】
    14 >>>3 任务返回运行结果,当前任务时间【1030毫秒】
    15 >>>4 任务终止
    16 >>>4 任务返回运行结果,当前任务时间【1030毫秒】
    17 ----程序结束运行----,程序运行时间【1146毫秒】
    示例2结果
     1 package com.testthread.test;
     2 
     3 import java.util.ArrayList;
     4 import java.util.HashMap;
     5 import java.util.List;
     6 import java.util.Map;
     7 import java.util.concurrent.Callable;
     8 import java.util.concurrent.ExecutionException;
     9 import java.util.concurrent.ExecutorService;
    10 import java.util.concurrent.FutureTask;
    11 
    12 import static java.util.concurrent.Executors.newFixedThreadPool;
    13 
    14 public class Test2 {
    15 
    16     public static void main(String[] args) {
    17         Map<String, Object> resultMap = new HashMap<>();
    18         int count = 10;
    19         ExecutorService executorService = newFixedThreadPool(10);
    20         long start = System.currentTimeMillis();
    21         try {
    22             List<FutureTask> list = new ArrayList();
    23             for (int i = 0; i < count; i++) {
    24                 FutureTask<Map<String, Object>> result = new FutureTask<Map<String, Object>>(myCall(i + ""));
    25                 executorService.submit(result);
    26                 list.add(result);
    27             }
    28             for (int i = 0; i < count; i++) {
    29                 Map<String, Object> resultMapShow = (Map<String, Object>) list.get(i).get();
    30                 System.out.println("resultMapShow = " + resultMapShow);
    31                 Map<String, Object> body = (Map<String, Object>) resultMapShow.get("body");
    32                 resultMap.put("aa" + i, body.get("aa"));
    33             }
    34             System.out.println("====>took:" + (System.currentTimeMillis() - start));
    35 
    36         } catch (InterruptedException e) {
    37             e.printStackTrace();
    38         } catch (ExecutionException e) {
    39             e.printStackTrace();
    40         } finally {
    41             executorService.shutdown();
    42         }
    43         System.out.println("resultMap = " + resultMap);
    44         System.out.println("==>took:" + (System.currentTimeMillis() - start));
    45     }
    46 
    47 
    48     public static Callable<Map<String, Object>> myCall(String taskId) {
    49         Callable<Map<String, Object>> callable = new Callable<Map<String, Object>>() {
    50             @Override
    51             public Map<String, Object> call() throws Exception {
    52                 return queryMethod(taskId);
    53             }
    54         };
    55         return callable;
    56     }
    57 
    58     private static Map<String, Object> queryMethod(String taskId) {
    59         try {
    60             System.out.println(" ==>任务启动" + taskId);
    61             long startI = System.currentTimeMillis();
    62             Thread.sleep(500);
    63 //            System.out.println("   sleep:500ms");
    64             System.out.println(" ==>任务终止" + taskId + " 任务时间:" + (System.currentTimeMillis() - startI));
    65         } catch (InterruptedException e) {
    66             e.printStackTrace();
    67         }
    68         Map<String, Object> resultMap = new HashMap<>();
    69         Map<String, Object> head = new HashMap<>();
    70         head.put("retFlag", "0000");
    71         head.put("retMsg", "成功");
    72         Map<String, Object> body = new HashMap<>();
    73         body.put("aa", "11");
    74         resultMap.put("head", head);
    75         resultMap.put("body", body);
    76         return resultMap;
    77     }
    78 }
    示例3
     1  ==>任务启动0
     2  ==>任务启动1
     3  ==>任务启动2
     4  ==>任务启动3
     5  ==>任务启动4
     6  ==>任务启动5
     7  ==>任务启动6
     8  ==>任务启动7
     9  ==>任务启动8
    10  ==>任务启动9
    11  ==>任务终止0 任务时间:501
    12 resultMapShow = {head={retMsg=成功, retFlag=0000}, body={aa=11}}
    13  ==>任务终止4 任务时间:502
    14  ==>任务终止3 任务时间:502
    15  ==>任务终止2 任务时间:502
    16  ==>任务终止1 任务时间:502
    17 resultMapShow = {head={retMsg=成功, retFlag=0000}, body={aa=11}}
    18 resultMapShow = {head={retMsg=成功, retFlag=0000}, body={aa=11}}
    19 resultMapShow = {head={retMsg=成功, retFlag=0000}, body={aa=11}}
    20 resultMapShow = {head={retMsg=成功, retFlag=0000}, body={aa=11}}
    21  ==>任务终止6 任务时间:502
    22  ==>任务终止5 任务时间:502
    23 resultMapShow = {head={retMsg=成功, retFlag=0000}, body={aa=11}}
    24 resultMapShow = {head={retMsg=成功, retFlag=0000}, body={aa=11}}
    25  ==>任务终止8 任务时间:501
    26  ==>任务终止7 任务时间:501
    27 resultMapShow = {head={retMsg=成功, retFlag=0000}, body={aa=11}}
    28 resultMapShow = {head={retMsg=成功, retFlag=0000}, body={aa=11}}
    29  ==>任务终止9 任务时间:501
    30 resultMapShow = {head={retMsg=成功, retFlag=0000}, body={aa=11}}
    31 ====>took:525
    32 resultMap = {aa1=11, aa0=11, aa3=11, aa2=11, aa5=11, aa4=11, aa7=11, aa6=11, aa9=11, aa8=11}
    33 ==>took:526
    示例3结果

    关系图:

    下面是关系图,望有助理解

     转自:https://blog.csdn.net/sinat_39634657/article/details/81456810

    https://blog.csdn.net/u012894692/article/details/80215140

    https://blog.csdn.net/rexueqingchun/article/details/79025882

  • 相关阅读:
    python的thread模块作用
    Python2、3解释器inpurt()函数的区别
    python中的单例设计模式
    Python2、3解释器中字符串中的区别
    浏览器向服务器发送请求的请求头解析
    Python中输出函数print()的三个参数
    Python中四种交换两个变量的值的方法
    学习爬虫看着篇(基础篇)
    Python读写txt文件时的编码问题
    网页和自然语言处理中的字符问题(半角和全角)
  • 原文地址:https://www.cnblogs.com/zt007/p/10339203.html
Copyright © 2020-2023  润新知