(十)java併發程式設計--建立和啟動執行緒(java.lang.Thread 、java.lang.Runnable)
執行緒建立的幾種方式.
建立和啟動一個執行緒
建立一個執行緒.
Thread thread = new Thread();
啟動java執行緒.
thread.start();
這兩個例子並沒有執行執行緒執行體,執行緒將會啟動後然後立即停止。
有兩種方式可以指定執行緒要執行的執行緒體。
1 、建立Thread的子類並且重寫run()方法。
2、一個物件實現Runnable介面。
執行緒的子類實現方式
第一種方式執行執行緒執行一些程式碼,是建立執行緒的子類,並且重寫Thread父類的方法run()方法。run()方法在我們呼叫start()方法後將會被執行。
如下程式碼:
package thread_create;
/**
* Created by fang on 2017/12/1.
* 執行緒建立的第一種方式,繼承Thread類,並實現run()方法.
*/
public class MyThread extends Thread{
public void run(){
System.out.println("MyThread running");
}
}
建立和啟動執行緒上面的執行緒體。
MyThread myThread = new MyThread();
myThread.start();
start() 方法呼叫將會立刻返回只要執行緒啟動了。它不會等待run()方法執行完成,run()方法可能將被不同的cup執行。當run() 方法執行後會打印出“MyThread running”。
我們也可以使用匿名子類,如下程式碼。
Thread thread = new Thread(){
public void run(){
System.out.println("Thread running");
}
};
thread.start();
Runnable 介面實現方式
第二種方式執行執行緒的程式碼可以建立一個類實現java.lang.Runnable。Runnable的子類物件能夠被一個執行緒執行。
example:
package thread_create;
/**
* Created by fang on 2017/12/1.
* 第二種方式實現Runable介面
*/
public class MyRunnable implements Runnable{
public void run() {
System.out.println("MyRunnable running");
}
}
run() 方法將被一個執行緒執行,傳遞例項物件MyRunnable 給一個執行緒的構造方法,如下程式碼.
Thread thread = new Thread(new MyRunnable());
thread.start();
執行緒開始將會呼叫run()方法,MyRunnable()例項將會替代Thread自己的run()方法,會打印出”MyRunnable running”.
我們可以可以使用匿名類實現介面.
// 匿名類實現介面.
Runnable myRunnable = new Runnable() {
public void run() {
System.out.println("Runnable running");
}
};
Thread thread1 = new Thread(myRunnable);
thread1.start();
繼承還是使用Runnable?
Runnable和Thread關係圖如下:
沒有規定那個最好,這兩種方式都可以。個人認為,我更喜歡使用Runnable,Thread將會獲得實現Runnable介面的例項。當我們使用執行緒池的時候,很容易將
Runnable例項排好隊,直到池中空閒。但對於執行緒子類來說有些困難。
通常的陷阱:呼叫run()方法替代start()
當我們建立和開始一個執行緒的時候可能直接呼叫run()方法替代呼叫start()方法,如下。
Thread newThread = new Thread(myRunnable);
newTherad.run();
執行的時候我們可能發現run()方法執行的和我們期望的一樣,但是它並不是我們自己啟動的執行緒執行的,而是由執行上述兩行程式碼的執行緒執行的,例如可以能是在main()主執行緒中執行的。如果我們想要使用我們newThread所呼叫的Runnable中的run()方法,必須使用newThead.run();
執行緒的名字
當你建立一個java執行緒,我們可以給執行緒給名字. 執行緒的名字能夠幫助我們區分執行緒之間的不同. 例如,如果多執行緒中我們可以通過System.out 輸出執行緒的名字,我們可以看到哪個執行緒在執行,例如.
//匿名類方式.
Thread thread = new Thread("New Thread"){
public void run(){
System.out.println("run by:" + getName());
}
};
thread.start();
System.out.println(thread.getName());
使用Runnable方式也可以傳遞執行緒的名字.如下程式碼
Thread thread = new Thread(new MyRunnable(),"New Thread");
thread.start();
System.out.println(thread.getName());
MyRunnable 類不是Thread的子類,它不能訪問執行它執行緒的getName()方法.
Thread.currentThread()
currentThread()方法返回正在執行currnetThread()執行緒的例項引用。通過這種方式,可以訪問java的執行緒物件,該物件表示執行給定程式碼塊的執行緒。
如下例項
String threadName = Thread.currentThread().getName();
System.out.println("當前執行緒名稱" +threadName);
java 執行緒例子
package thread_create;
/**
* Created by fang on 2017/12/1.
*/
public class ThreadExample {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());
for(int i=0;i<10;i++){
new Thread(" "+i){
public void run(){
System.out.println("Thread: " + getName() + " running" );
}
}.start();
}
}
}
執行結果:
main
Thread: 0 running
Thread: 1 running
Thread: 2 running
Thread: 4 running
Thread: 3 running
Thread: 6 running
Thread: 5 running
Thread: 7 running
Thread: 9 running
Thread: 8 running
Process finished with exit code 0
即使執行緒按照順序啟動的(start()),但是它們可能不會按照順序執行,這意味著執行緒1可能不是第一個將其名稱寫入System.out的執行緒,這是因為執行緒在原則上是並行執行的,而不是按照順序執行的。JVM和作業系統決定了執行緒的執行順序,這個順序不必是它們開始的順序。所以可能會輸出如上結果。
執行緒宣告異常和執行緒體的返回值?Callable、Future使用
上述兩種方式線上程執行體run()方法上並沒有執行緒的返回值,以及可以對外宣告異常.
Java 5引入了Java.util.concurrent。併發包中的可呼叫介面,它類似於Runnable介面,但它可以返回任何物件,並能夠丟擲異常。
這篇有些長,下一篇使用Callable 和Future完成攜帶返回值的執行緒建立.