runnable函数java_Java线程—-Runnable和Callable的区别和联系

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

1.继承Thread接口

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 public classThread2Thread {2 public static voidmain(String[] args) {3 newMyThread1().start();4 new Thread(new MyThread1(), "线程2").start();5 }6 }7

8 /**

9 * 通过继承Thread类10 */

11 class MyThread1 extendsThread {12 /**

13 * 重写run方法14 */

15 @Override16 public voidrun() {17 //TODO Auto-generated method stub

18 super.run();19 }20 }

通过继承Thread类

2.实现Runnable接口

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagecom.testthread.demo4;2

3 importjava.util.concurrent.ExecutorService;4

5 import static java.util.concurrent.Executors.*;6

7 public classThread2Runnable {8

9 public static voidmain(String[] args) {10

11 //case1:通过实现Runnable接口,来实现run方法的具体逻辑

12 new Thread(new MyThread2(), "线程1").start();13 //case2:匿名内部类

14 new Thread(newRunnable() {15 @Override16 public voidrun() {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 = newMyThread2();27 executor.execute(myThread2);28 executor.shutdown();29 }30 }31

32 /**

33 * 实现Runnable接口的线程类34 */

35 class MyThread2 implementsRunnable {36

37 /**

38 * 重写run方法39 */

40 @Override41 public voidrun() {42 //TODO Auto-generated method stub

43 }44 }

实现Runnable接口

3.通过Callable和Future创建线程

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 importjava.util.concurrent.Callable;2 importjava.util.concurrent.FutureTask;3

4 public classThread2Callable {5 public static voidmain(String[] args) {6 //创建 Callable 实现类的实例

7 MyCallable myCallable = newMyCallable();8 //使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值

9 FutureTask futureTask = new FutureTask(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{27

28 /**

29 * 该 call() 方法将作为线程执行体,并且有返回值30 */

31 @Override32 public String call() throwsException {33 return "success";34 }35 }

通过Callable和Future创建线程

Runnable和Callable的区别和联系

Runnable

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

Runnable的声明如下 :

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 public interfaceRunnable {2 /*

3 * @see java.lang.Thread#run()4 */

5 public abstract voidrun();6 }

Runnable

#Callable

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

Callable的声明如下 :

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 public interface Callable{2 /**

3 * Computes a result, or throws an exception if unable to do so.4 *5 *@returncomputed result6 *@throwsException if unable to compute a result7 */

8 V call() throwsException;9 }

View Code

#Future

Executor就是Runnable和Callable的调度容器,Future就是对于具体的Runnable或者Callable任务的执行结果进行

取消、查询是否完成、获取结果、设置结果操作。get方法会阻塞,直到任务返回结果(Future简介)。

Future声明如下 :

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 public interface Future{2

3 /**

4 * Attempts to cancel execution of this task. This attempt will5 * 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 cancel is called,8 * this task should never run. If the task has already started,9 * then the mayInterruptIfRunning parameter determines10 * whether the thread executing this task should be interrupted in11 * an attempt to stop the task.12 */

13 boolean cancel(booleanmayInterruptIfRunning);14

15 /**

16 * Returns true if this task was cancelled before it completed17 * normally.18 */

19 booleanisCancelled();20

21 /**

22 * Returns true if this task completed.23 *24 */

25 booleanisDone();26

27 /**

28 * Waits if necessary for the computation to complete, and then29 * retrieves its result.30 *31 *@returnthe computed result32 */

33 V get() throwsInterruptedException, ExecutionException;34

35 /**

36 * Waits if necessary for at most the given time for the computation37 * to complete, and then retrieves its result, if available.38 *39 *@paramtimeout the maximum time to wait40 *@paramunit the time unit of the timeout argument41 *@returnthe computed result42 */

43 V get(longtimeout, TimeUnit unit)44 throwsInterruptedException, ExecutionException, TimeoutException;45 }

Future

#FutureTask(很有用)

FutureTask是一个RunnableFuture

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 public class FutureTask implements RunnableFuture

FutureTask

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 public interface RunnableFuture extends Runnable, Future{2 /**

3 * Sets this Future to the result of its computation4 * unless it has been cancelled.5 */

6 voidrun();7 }

RunnableFuture

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 public FutureTask(Callablecallable) {2 if (callable == null)3 throw newNullPointerException();4 this.callable =callable;5 this.state = NEW; //ensure visibility of callable

6 }7

8 publicFutureTask(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类型的任务。

该适配函数的实现如下 :

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 public static Callablecallable(Runnable task, T result) {2 if (task == null)3 throw newNullPointerException();4 return new RunnableAdapter(task, result);5 }

callable

RunnableAdapter适配器

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 /**

2 * A callable that runs given task and returns given result3 */

4 static final class RunnableAdapter implements Callable{5 finalRunnable task;6 finalT result;7 RunnableAdapter(Runnable task, T result) {8 this.task =task;9 this.result =result;10 }11 publicT call() {12 task.run();13 returnresult;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()得到,此方法会阻塞主进程的继续往下执行,如果不调用不会阻塞。

示例:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagecom.xzf.callable;2

3 importjava.util.concurrent.Callable;4 importjava.util.concurrent.ExecutorService;5 importjava.util.concurrent.Executors;6 importjava.util.concurrent.Future;7 importjava.util.concurrent.FutureTask;8

9 public classRunnableFutureTask {10 static ExecutorService executorService = Executors.newSingleThreadExecutor(); //创建一个单线程执行器

11 public static voidmain(String[] args) {12 runnableDemo();13 futureDemo();14 }15 /**

16 * new Thread(Runnable arg0).start(); 用Thread()方法开启一个新线程17 * runnable, 无返回值18 */

19 static voidrunnableDemo() {20 new Thread(newRunnable() {21 public voidrun() {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 voidfutureDemo() {35 try{36 Future> result1 = executorService.submit(newRunnable() {37 public voidrun() {38 fibc(20);39 }40 });41 System.out.println("future result from runnable:"+result1.get()); //run()无返回值所以为空,result1.get()方法会阻塞

42 Future result2 = executorService.submit(new Callable() {43 public Integer call() throwsException {44 return fibc(20);45 }46 });47 System.out.println("future result from callable:"+result2.get()); //call()有返回值,result2.get()方法会阻塞

48 FutureTask result3 = new FutureTask(new Callable() {49 public Integer call() throwsException {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 result4 = new FutureTask(newRunnable() {58 public voidrun() {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 result5 = new FutureTask(newRunnable() {67 public voidrun() {68 fibc(20);69 }70 },fibc(20));71 newThread(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(intnum) {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

运行结果:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagecom.testthread.test;2

3 import java.util.concurrent.*;4 importjava.util.Date;5 importjava.util.List;6 importjava.util.ArrayList;7

8 public class Test implements Callable{9 privateString taskNum;10

11 Test(String taskNum) {12 this.taskNum =taskNum;13 }14

15 public static voidmain(String[] args) {16 System.out.println("----程序开始运行----");17 Date date1 = newDate();18 int taskSize = 5; //创建一个线程池

19 ExecutorService pool = Executors.newFixedThreadPool(taskSize); //创建多个有返回值的任务

20 List list = new ArrayList();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 = newDate();40 System.out.println("----程序结束运行----,程序运行时间【" + (date2.getTime() - date1.getTime()) + "毫秒】");41 }42

43 @Override44 public Object call() throwsException {45 System.out.println(">>>" + taskNum + "任务启动");46 Date dateTmp1 = newDate();47 Thread.sleep(1000);48 Date dateTmp2 = newDate();49 long time = dateTmp2.getTime() -dateTmp1.getTime();50 System.out.println(">>>" + taskNum + "任务终止");51 return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】";52 }53 }

示例2

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

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结果

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagecom.testthread.test;2

3 importjava.util.ArrayList;4 importjava.util.HashMap;5 importjava.util.List;6 importjava.util.Map;7 importjava.util.concurrent.Callable;8 importjava.util.concurrent.ExecutionException;9 importjava.util.concurrent.ExecutorService;10 importjava.util.concurrent.FutureTask;11

12 import staticjava.util.concurrent.Executors.newFixedThreadPool;13

14 public classTest2 {15

16 public static voidmain(String[] args) {17 Map resultMap = new HashMap<>();18 int count = 10;19 ExecutorService executorService = newFixedThreadPool(10);20 long start =System.currentTimeMillis();21 try{22 List list = newArrayList();23 for (int i = 0; i < count; i++) {24 FutureTask> result = new FutureTask>(myCall(i + ""));25 executorService.submit(result);26 list.add(result);27 }28 for (int i = 0; i < count; i++) {29 Map resultMapShow = (Map) list.get(i).get();30 System.out.println("resultMapShow = " +resultMapShow);31 Map body = (Map) 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>myCall(String taskId) {49 Callable> callable = new Callable>() {50 @Override51 public Map call() throwsException {52 returnqueryMethod(taskId);53 }54 };55 returncallable;56 }57

58 private static MapqueryMethod(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 resultMap = new HashMap<>();69 Map head = new HashMap<>();70 head.put("retFlag", "0000");71 head.put("retMsg", "成功");72 Map body = new HashMap<>();73 body.put("aa", "11");74 resultMap.put("head", head);75 resultMap.put("body", body);76 returnresultMap;77 }78 }

示例3

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 ==>任务启动02 ==>任务启动13 ==>任务启动24 ==>任务启动35 ==>任务启动46 ==>任务启动57 ==>任务启动68 ==>任务启动79 ==>任务启动810 ==>任务启动911 ==>任务终止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结果

关系图:

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

0a6b1d58cee530a4e1472054b8be4678.png

f973ca522eba3ff72f3d7bbcf292c52e.png

转自: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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值