1:三个新加的多线程包 Java 5.0里新加入了三个多线程包:java.util.concurrent, java.util.concurrent.atomic, java.util.concurrent.locks.
! x* S n& h1 d6 y7 }, ]6 s java.util.concurrent包含了常用的多线程工具,是新的多线程工具的主体。4 X1 h$ R5 i, H1 |1 _
java.util.concurrent.atomic包含了不用加锁情况下就能改变值的原子变量,比如说AtomicInteger提供了addAndGet()方法。Add和Get是两个不同的操作,为了保证别的线程不干扰,以往的做法是先锁定共享的变量,然后在锁定的范围内进行两步操作。但用AtomicInteger.addAndGet()就不用担心锁定的事了,其内部实现保证了这两步操作是在原子量级发生的,不会被别的线程干扰。' {/ y: L0 F9 @2 o- _3 Q
java.util.concurrent.locks包包含锁定的工具。
% D4 s% W: ] o3 T 2:Callable 和 Future接口2 e/ n8 |3 H( T# d
Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。Callable和Runnable有几点不同:9 z' H! D4 c, F g* |" C" P5 o- F
Callable规定的方法是call(),而Runnable规定的方法是run().
4 U/ H/ [4 S/ D) A" F Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。9 D: Q5 h6 f4 b2 w
call()方法可抛出异常,而run()方法是不能抛出异常的。
& Q, _( E Y4 m0 }6 Q5 s- d& { 运行Callable任务可拿到一个Future对象,通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。& L0 E) [+ r& D \. g) A0 E
以下是Callable的一个例子:
& C/ q6 Q# h) s5 H/ M+ B public class DoCallStuff implements Callable{ // *1
' O" Q5 N0 z0 U9 |: K private int aInt;0 `, q5 G* w& k6 e
public DoCallStuff(int aInt) {
0 Y/ {3 l% Z9 v0 |9 F this.aInt = aInt;& q- `7 H+ f/ I
}
# r) P5 _8 t, U, ~4 I public String call() throws Exception { //*2: B% P% A( E* E( f7 V
boolean resultOk = false;2 h$ D) t, W+ v8 U; V1 Y
if(aInt == 0){3 o$ i3 V1 _# E: E( l) v6 Q. f
resultOk = true;
& x( ^& k; B2 Q, b; j$ a4 G8 Y } else if(aInt == 1){
8 n" U! B$ T; A& \7 A) t while(true){ //infinite loop
. T( N. ? O" F8 u System.out.println("looping....");
: F0 Z. k6 v- h$ b6 }6 X$ O Thread.sleep(3000);
% k( k! O; X* o; s }
8 D3 C, b- ]8 U } else {9 ^! F: F- x2 Q8 N* }6 p* H
throw new Exception("Callable terminated with Exception!"); //*38 D* N0 l" f- {, D' K: s3 ~# H2 F/ C
}
. z% H7 W- o0 U, ]0 n if(resultOk){
, A6 M, q, v7 c: Q: g return "Task done.";- b" R$ j _( E" }
} else {
. x0 m7 d3 @/ l; z return "Task failed";) v# E3 o! s; C+ c/ }
}
; w5 i7 j9 S; J2 g }5 Q' I7 B! `( h- `" i
}! Y, [2 D7 G; L
*1: 名为DoCallStuff类实现了Callable,String将是call方法的返回值类型。例子中用了String,但可以是任何Java类。: }$ ]) t0 X. G6 h% w5 m
*2: call方法的返回值类型为String,这是和类的定义相对应的。并且可以抛出异常。4 T$ W7 [' A6 E& e T3 T
*3: call方法可以抛出异常,如加重的斜体字所示。1 t) `( Y0 T) D4 k& }: A4 R% ?/ X
以下是调用DoCallStuff的主程序。
" v [( c# V V9 i4 C6 y import java.util.concurrent.ExecutionException;
8 {4 ` P, e# e$ j import java.util.concurrent.ExecutorService;7 T5 J; C8 L, L% E
import java.util.concurrent.Executors;
8 t8 k! ^. M+ ^; Y% k import java.util.concurrent.Future;2 T+ C( R5 \* f. ?, B
public class Executor {
" s2 y4 G' o' ?, h! }! n4 n public static void main(String[] args){
3 s5 T$ T3 E) ~( ^: ~ //*1
' s6 o$ U3 A5 V" J3 T$ z# U7 L; b DoCallStuff call1 = new DoCallStuff(0);: m" }, ]) q6 Z# K1 y' J7 L
DoCallStuff call2 = new DoCallStuff(1);
7 P* s$ F0 y0 Z' R% k0 Q DoCallStuff call3 = new DoCallStuff(2);* Y; T. e# C' L* z2 |3 X
//*2
1 r0 g7 a- L3 l/ c$ [) e ExecutorService es = Executors.newFixedThreadPool(3);0 X2 M l5 l6 [+ ?, F# s
//*35 a% D6 p7 s) C; d
Future future1 = es.submit(call1);
6 F/ N- M, D, y. M9 b$ j Future future2 = es.submit(call2); Z* k6 v2 G; L( W8 H7 m5 T7 v
Future future3 = es.submit(call3);
5 y0 W8 N8 }- o/ X" H3 m" B! ]! k try {
1 K2 L- m$ X; R* U$ ]) R //*4& V0 j7 u. Q+ T2 d
System.out.println(future1.get());
2 o" D F, y, f //*5
( d8 \* F0 x J9 @, U7 X t } Thread.sleep(3000);( c1 n9 Z) m8 b5 F- S
System.out.println("Thread 2 terminated? :" + future2.cancel(true));
* I/ |: c3 R0 Z9 m Y //*6
0 x' W8 K* O/ C0 p System.out.println(future3.get());
+ u/ L6 y7 A9 Z } catch (ExecutionException ex) {+ j& U: a/ E- F: ?
ex.printStackTrace();
8 _' ?& U5 W! s, b/ t9 T- g } catch (InterruptedException ex) {
$ \! f. ^5 _9 D; t ex.printStackTrace();. X* Y; g7 G5 X$ }6 _2 U
}* n9 s0 `& a( Y4 x, w2 v: d7 T
}+ `) z1 r+ m8 P" f1 O$ i
}3 X/ `' R0 g/ l( Y
*1: 定义了几个任务
1 U7 e( d7 k2 D/ Q3 B *2: 初始了任务执行工具。任务的执行框架将会在后面解释。
8 H5 W) a2 [7 L4 A *3: 执行任务,任务启动时返回了一个Future对象,如果想得到任务执行的结果或者是异常可对这个Future对象进行操作。Future所含的值必须跟Callable所含的值对映,比如说例子中Future对印Callable7 w. ~3 l/ H r) r
*4: 任务1正常执行完毕,future1.get()会返回线程的值
% @* h: I s/ ?6 |1 p. _8 o0 R" P *5: 任务2在进行一个死循环,调用future2.cancel(true)来中止此线程。传入的参数标明是否可打断线程,true表明可以打断。
% `5 N* @! G1 Q; w *6: 任务3抛出异常,调用future3.get()时会引起异常的抛出。5 i/ m" E! d& `; b& l( O
运行Executor会有以下运行结果:
% S& U: \1 {# C3 b2 c2 u looping....0 V& `4 m. i4 l3 {, `9 i- S# ?
Task done. //*11 Y) U- d% U$ V8 r. T- k
looping....
! M$ w d9 h0 [7 s$ _ f% b looping....//*2
4 @' s7 d8 q6 f: q4 y looping....
& t9 ]8 H' P# g9 n looping....
! A8 l/ E4 _( E. T- M) x looping....
: |7 N" b' e! Y( v- p6 l. Z looping....
) j, G; F* B/ V- v8 n! \ Thread 2 terminated? :true //*3
6 f% g9 W6 l; |. s //*4
( N( k2 k* y; _, L3 q' ~2 a java.util.concurrent.ExecutionException: java.lang.Exception: Callable terminated with Exception!
7 Z \ Z8 t. V" K& \ at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:205)
' U: L9 k( X4 O& Y! Z at java.util.concurrent.FutureTask.get(FutureTask.java:80)
5 q' }8 e) f% J at concurrent.Executor.main(Executor.java:43)
+ A8 C x: ]- J5 i ……. |