建立有執行緒的方法
一般執行緒實作建立可用兩種:
1. 透過 implements 實作 Runnable 介面
class Pi implements Runnable{ ...
2. 透過 extends 繼承 Thread 類別
class Pi extends Thread{ ...
完成後,兩者皆要實作 run 這個方法(Override)
@Override public void run(){ ...
所以說,"run" 這個方法將會成為每次要建立這個物件的執行緒時,首要進入的方法。
* run 不可以拋出例外(throws),而且不建議重寫原本的方法,所以裡面發生例外就必須寫 try catch。
* 以上兩者實作的方法用途皆相同,但寫extends可能會因為您的物件有其他父類別要繼承,故常用 implements 來時做 Runnable 介面達成!
實作執行緒方法
1. 使用第一種方式 (implements)來實作執行緒:public class Main{ public static void main(String[] args) { Thread t1 = new Thread(new Pi()); t1.start(); Thread t2 = new Thread(new Pi()); t2.start(); } } class Pi implements Runnable{ @Override public void run(){ System.out.println("Thread ID:"+Thread.currentThread().getName()+" print 3.1415926"); } }
2. 使用第二種方式 (extends)來實作執行緒:
public class Main{ public static void main(String[] args) { Thread t1 = new Thread(new Pi()); t1.start(); //also can use: Pi pi = new Pi(); pi.start(); } } class Pi extends Thread{ @Override public void run(){ System.out.println("Thread ID:"+Thread.currentThread().getName()+" print 3.1415926"); } }
兩者皆可得出結果:
Thread ID:Thread-0 print 3.1415926
Thread ID:Thread-1 print 3.1415926
若要設定執行緒 ID, 可以透過:
... t1.setName("第一執行緒"); pi.setName("第二執行緒"); ...
結果可得:
Thread ID:第一執行緒 print 3.1415926
Thread ID:第二執行緒 print 3.1415926
停止等待方法
若希望程式暫時停止幾秒鐘,可以透過以下方法:Thread.sleep(2000); //stop 2000 million seconds這是一個靜態的方法,直接呼叫即可。
執行緒讓出 (yield)
*以下全部使用 implements 實作的方式來作範例若不希望目前執行緒繼續執行,可以於 run() 裡面,使用 yield() 來讓出,但是一次只能讓出一次,如果要實現多次讓出,請用迴圈(while)。
public void run(){ for (int i = 0; i <2147483647; i++) { Thread.yield(); } System.out.println("Thread ID:"+Thread.currentThread().getName()+" print 3.1415926"); }
*yield 也是一個靜態的方法,直接呼叫 Thread.yield() 即可,若您是使用 extends 來時做,您也可以用 yield() 。
凍結等待其他執行緒方法 (join)
* 為了說明其功用,以下是範例 code:class Pi implements Runnable{ @Override public void run(){ Thread processor = new Thread(new MathMachine()); System.out.println("交給機器運算..."); processor.start(); System.out.println("OK, Thread ID:"+Thread.currentThread().getName()+" print 3.1415926"); } } class MathMachine implements Runnable{ @Override public void run(){ System.out.println("PI 運算完成"); } }
先列出結果:
交給機器運算...
OK, Thread ID:第一執行緒 print 3.1415926
PI 運算完成
其實可以發現上方的結果已經有問題了,程序應該是等待 MathMachine 運算完成才能執行顯示動作,這時候就可以使用 join 這個方法,優先讓 MathMachine 執行:
... processor.start(); try { processor.join(); } catch (InterruptedException ex) { } System.out.println("OK, Thread ID:"+Thread.currentThread().getName()+" print 3.1415926"); ...使用 processor.join(), 就可以優先讓數學機器(MathMachine)執行完,再執行下列方法,其實就是將 Pi 這個類別的執行緒進入凍結狀態,等待 MathMachine 執行緒完成後,才解除 Pi 的凍結狀態回到執行緒中。
*使用 join 將會拋出一個 Interrupted 的例外,在此不做處理
正確結果為:
交給機器運算...
PI 運算完成
OK, Thread ID:第一執行緒 print 3.1415926
另外有幾種運算子,不多做介紹:
wait() <-- 針對呼叫這個方法的原方法,把執行緒做暫停等待
notify() <-- 隨意把目前暫停的方法呼叫繼續執行
若程式中沒有良好的機制喚醒使用 wait() 的方法,那麼程式可能就會互相一直等待(dead lock)。
synchronized 運算子,可以使用範圍的synchronized:
synchronized(this){ }這個做法是範圍技,可以鎖定需要的物件做同步化 (this這行鎖定物件)。
或是在方法宣告中,加上 synchronized:
public synchronized void HelloWorld(){ ...
所有使用這個方法的傢伙,不管是多執行緒,一次就只能一個處理 / 存取這個項目,舉個例子就是 ATM, 總不能兩個人同時存錢又取錢,結果資料被覆蓋了吧?
沒有留言:
張貼留言