1、Runnable和Callable的区别
(1) Callable规定的方法是 call(), Runnable规定的方法是 run()。
(2) Callable的任务执行后可返回值,而 Runnable的任务是不能返回值。
(3) call方法可以抛出异常, run方法不可以。
(4)运行 Callable任务可以拿到一个 Future对象
Future表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get方法来获取结果,如果线程没有执行完, Future.get()方法可能会阻塞当前线程的执行;如果线程出现异常, Future.get()会 throws InterruptedException或者 ExecutionException;如果线程已经取消,会跑出 CancellationException。取消由 cancel方法来执行。
isDone确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算。如果为了可取消性而使用 Future但又不提供可用的结果,则可以声明 Future <?> 形式类型、并返回null作为底层任务的结果。
Future接口的定义如下:
Future模式在请求发生时,会先产生一个 Future凭证给发出请求的客户,它的作用就像是 Proxy物件,同时,由一个新的执行线程持续进行目标物件的生成( Thread - Per - Message),真正的目标物件生成之后,将之设定至 Future之中,而当客户端真正需要目标物件时,目标物件也已经准备好,可以让客户提取使用。
结合 JDK的 Future来看,就是你 run线程后,你可以把线程的返回值赋给 Future并返回一个 Future对象。这时你可以立即拿到这个对象,然后进行下面的逻辑。但是如果你要 get这个 Future中的线程结果,就会被阻塞直到线程结束。
相当于现在的期房,你把手续和钱都交上去了,就可以马上拿到合同,但只有合同没有房子。这个时候你已经是有房一族了,你可以先去买家电买装修(走下面的其他逻辑)。但是你要把家电和装修放进去,就必须等到房子完工(阻塞)。
2、Callable实现:
submit方法会产生Future对象,它用Callable返回结果的特定类型进行了参数化,可以用isDone()的方法来查询Future是否已经完成。当任务完成是,它具有一个结果,可以调用get()方法来获取该结果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
package
zeze;
import
java.util.ArrayList;
import
java.util.concurrent.Callable;
import
java.util.concurrent.ExecutorService;
import
java.util.concurrent.Executors;
import
java.util.concurrent.Future;
/***
*
* @ClassName: EbayMultiplyThreadCheck
* @Description: TODO
* @author zeze
* @date 2017年2月16日 上午8:49:46
*
*/
public
class
EbayMultiplyThreadCheck {
public
static
void
main(String[] args) {
ExecutorService exec = Executors.newFixedThreadPool(
10
);
ArrayList<Future<String>> results =
new
ArrayList<Future<String>>();
for
(
int
i =
0
; i <
10
; i++) {
String email =
"asd"
+ i +
"@qq.com"
;
results.add(exec.submit(
new
TaskWithResult(email)));
}
boolean
isDone =
false
;
while
(!isDone) {
isDone =
true
;
for
(Future<String> future : results) {
if
(!future.isDone()) {
isDone =
false
;
try
{
Thread.sleep(
1000
);
}
catch
(InterruptedException e) {
}
break
;
}
}
}
exec.shutdown();
}
}
class
TaskWithResult
implements
Callable<String> {
private
String email;
public
TaskWithResult(String email) {
this
.email = email;
}
@Override
public
String call() {
System.out.println(email);
return
null
;
}
}
|
3、Runnable 实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
/**
* @Title: RunnableDemo.java
* @Package zeze
* @Description: TODO(用一句话描述该文件做什么)
* @author A18ccms A18ccms_gmail_com
* @date 2017年3月13日 下午4:08:09
* @version V1.0
*/
package
zeze;
import
java.util.concurrent.ExecutorService;
import
java.util.concurrent.Executors;
import
javafx.animation.Animation.Status;
/**
* @ClassName: RunnableDemo
* @Description: TODO
* @author zeze
* @date 2017年3月13日 下午4:08:09
*
*/
public
class
RunnableDemo
implements
Runnable {
protected
int
countDown =
10
;
private
static
int
taskCount =
0
;
private
final
int
id = taskCount++;
public
RunnableDemo() {
}
public
RunnableDemo(
int
countDown) {
this
.countDown = countDown;
}
public
String status() {
return
"#"
+ id +
"("
+ (countDown >
0
? countDown :
"LiftOff!"
) +
")."
;
}
@Override
public
void
run() {
while
(countDown-- >
0
) {
System.out.print(status());
Thread.yield();
// 将CPU从一个线程转移给另一个线程
}
}
public
static
void
main(String[] args) {
System.out.println(
"这个任务的run()不是单独的线程驱动,是在main()中直接调用"
);
RunnableDemo launch =
new
RunnableDemo();
launch.run();
System.out.println();
System.out.println(
"************************************"
);
System.out.println(
"在新线程中启动任务"
);
Thread thread =
new
Thread(
new
RunnableDemo());
thread.start();
System.out.println(
"Waiting for LiftOff"
);
System.out.println(
"************************************"
);
System.out.println(
"添加多个线程去驱动更多的任务"
);
for
(
int
i =
0
; i <
5
; i++) {
new
Thread(
new
RunnableDemo()).start();
}
System.out.println(
"Waiting for LiftOff"
);
System.out.println(
"************************************"
);
System.out.println(
"使用executor"
);
ExecutorService exec = Executors.newCachedThreadPool();
exec=Executors.newFixedThreadPool(
5
);
for
(
int
i =
0
; i <
5
; i++) {
exec.execute(
new
RunnableDemo());
}
exec.shutdown();
}
}
|