点个关注,必回关
文章目录
- 一、Java提供了三种创建线程的方法
- 1.继承Thread
- 2.实现Runnable接口
- 3.通过Callable和Future创建线程
- 二、Runnable和Callable的区别和联系
- 1.定义接口
- (1) Runnable
- (2)Callable
- (3)Future
- (4)FutureTask
- 2.相同点
- 3.不同点
- 4.示例
- (1)示例一
- (2) 运行结果:
- (3)示例二
- (4) 运行结果:
- (5)示例三
- (6) 运行结果:
- 5.关系图
- 图一:
- 图二:
一、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 }
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 }
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 }
二、Runnable和Callable的区别和联系
1.定义接口
(1) 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 }
(2)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 }
(3)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 }
(4)FutureTask
FutureTask是一个RunnableFuture
1 public class FutureTask<V> implements RunnableFuture<V>
RunnableFuture实现了Runnbale又实现了Futrue这两个接口
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 }
另外FutureTaslk还可以包装Runnable和Callable, 由构造函数注入依赖。
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 }
上面代码块可以看出: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 }
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 }
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 )。
2.相同点
1 都是接口
2 都可以编写多线程程序
3 都采用Thread.start()启动线程
3.不同点
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()得到,此方法会阻塞主进程的继续往下执行,如果不调用不会阻塞
4.示例
(1)示例一
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 }
(2) 运行结果:
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
(3)示例二
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 }
(4) 运行结果:
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毫秒】
(5)示例三
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 }
(6) 运行结果:
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