任務:
我們使用多線程,去執行的都是任務,那麼我們首先得學會如何定義一個任務。
public class LiftOff implements Runnable{
protected int countDown = 10;
private static int taskCount = 0;
private final int id = taskCount++;
public LiftOff(){}
public LiftOff(int countDown)
{
this.countDown = countDown;
}
public String status(){
return "#"+id+"("+(countDown>0?countDown:"liftOff!")+"),";
}
public void run(){
while(countDown-->0)
System.out.println(status());
Thread.yield();
}
}
這個任務類,實現了Runnable接口,然後覆蓋run()方法。這兩點是必須的。
如果,我們在main方法裏面,調用這個run方法,比如
public static void main(String args[]){
LiftOff launch = new LiftOff();
launch.run();
}
會輸出:
#0(9),
#0(8),
#0(7),
#0(6),
#0(5),
#0(4),
#0(3),
#0(2),
#0(1),
#0(liftOff!),
其實這裏雖然我們執行了一個任務(launch 實現了Runnable接口),但是這也不是我們今天要看的多線程。他就像一個普通的調用方法一樣在執行。整個執行過程中,只有main()一個線程,run()方法在main線程中執行。
那麼我們怎麼將這個任務變成多線程執行呢。
Thread類
那麼我們怎麼將這個任務變成多線程執行呢?將他交給Thread構造器。
public static void main(String args[]){
Thread t = new Thread(new LiftOff());
t.start();
System.out.println("wait for liftoff");
}
輸出:
wait for liftoff
#0(9),
#0(8),
#0(7),
#0(6),
#0(5),
#0(4),
#0(3),
#0(2),
#0(1),
#0(liftOff!),
如果我們沒有多線程的概念,還是停留在順序執行的思維中。會不會比較奇怪System.out.println("wait for liftoff");竟然在t.start()方法前面執行!
實際上Thread t = new Thread(new LiftOff()); t.start();這兩句是產生一個新的線程,然後去執行任務的run()方法。
這裏,我們就有了兩個線程,一個main函數的線程,一個run()方法的線程。那麼至於main()函數中之後的操作和run()方法以什麼樣子的順序執行。這個只能有線程調用器自動控制了。
main()中多幾個線程,我們看看究竟怎麼執行的
public static void main(String args[]){
for(int i=0;i<5;i++){
new Thread(new LiftOff()).start();
}
System.out.println("wait for liftoff");
}
這個程序執行多次,輸出是不一樣的。挑了一個比較亂的順序大家感受下
wait for liftoff
#2(9),
#3(9),
#4(9),
#1(9),
#2(8),
#1(8),
#4(8),
#0(9),
#3(8),
#0(8),
#4(7),
#1(7),
#2(7),
#1(6),
#4(6),
#4(5),
#0(7),
#3(7),
#0(6),
#4(4),
#1(5),
#2(6),
#1(4),
#4(3),
#0(5),
#3(6),
#0(4),
#4(2),
#1(3),
#2(5),
#1(2),
#4(1),
#0(3),
#3(5),
#0(2),
#4(liftOff!),
#1(1),
#2(4),
#1(liftOff!),
#0(1),
#0(liftOff!),
#3(4),
#2(3),
#3(3),
#2(2),
#3(2),
#2(1),
#3(1),
#2(liftOff!),
#3(liftOff!),
補充:從任務中返回值
實現了Runnable接口,覆蓋了run方法不會返回任何值,如果希望每個任務返回一個值。那就可以實現Callable接口,覆蓋call()方法。但是,必須使用ExecutorService.sunmit()方法調用他。ExecutorService.sunmit()用法見第二篇文章