多線程實(shí)現(xiàn)方式---實(shí)現(xiàn)Runnable接口多線程實(shí)現(xiàn)方式---實(shí)現(xiàn)Runnable接口一個(gè)類如果需要具備多線程的能力,,也可以通過(guò)實(shí)現(xiàn)java.lang.Runnable接口進(jìn)行實(shí)現(xiàn)。按照Java語(yǔ)言的語(yǔ)法,,一個(gè)類可以實(shí)現(xiàn)任意多個(gè)接口,,所以該種實(shí)現(xiàn)方式在實(shí)際實(shí)現(xiàn)時(shí)的通用性要比前面介紹的方式好一些。 使用實(shí)現(xiàn)Runnable接口實(shí)現(xiàn)多線程的示例代碼如下: /** * 測(cè)試類 */ public class Test2 { public static void main(String[] args) { //創(chuàng)建對(duì)象 MyRunnable mr = new MyRunnable(); Thread t = new Thread(mr); //啟動(dòng) t.start(); try{ for(int i = 0;i < 10;i++){ Thread.sleep(1000); System.out.println("main:" + i); } }catch(Exception e){} } } /** * 使用實(shí)現(xiàn)Runnable接口的方式實(shí)現(xiàn)多線程 */ public class MyRunnable implements Runnable { public void run() { try{ for(int i = 0;i < 10;i++){ Thread.sleep(1000); System.out.println("run:" + i); } }catch(Exception e){} } } 該示例代碼實(shí)現(xiàn)的功能和前面實(shí)現(xiàn)的功能相同,。在使用該方式實(shí)現(xiàn)時(shí),,使需要實(shí)現(xiàn)多線程的類實(shí)現(xiàn)Runnable,,實(shí)現(xiàn)該接口需要覆蓋run方法,然后將需要以多線程方式執(zhí)行的代碼書(shū)寫(xiě)在run方法內(nèi)部或在run方法內(nèi)部進(jìn)行調(diào)用。 在需要啟動(dòng)線程的地方,,首先創(chuàng)建MyRunnable類型的對(duì)象,,然后再以該對(duì)象為基礎(chǔ)創(chuàng)建Thread類的對(duì)象,最后調(diào)用Thread對(duì)象的start方法即可啟動(dòng)線程,。代碼如下: //創(chuàng)建對(duì)象 MyRunnable mr = new MyRunnable(); Thread t = new Thread(mr); //啟動(dòng) t.start(); 在這種實(shí)現(xiàn)方式中,,大部分和前面介紹的方式類似,啟動(dòng)的代碼稍微麻煩一些,。這種方式也是實(shí)現(xiàn)線程的一種主要方式,。 12.2.3使用Timer和TimerTask組合最后一種實(shí)現(xiàn)多線程的方式,就是使用java.util包中的Timer和TimerTask類實(shí)現(xiàn)多線程,,使用這種方式也可以比較方便的實(shí)現(xiàn)線程,。 在這種實(shí)現(xiàn)方式中,Timer類實(shí)現(xiàn)的是類似鬧鐘的功能,,也就是定時(shí)或者每隔一定時(shí)間觸發(fā)一次線程,。其實(shí),Timer類本身實(shí)現(xiàn)的就是一個(gè)線程,,只是這個(gè)線程是用來(lái)實(shí)現(xiàn)調(diào)用其它線程的,。而TimerTask類是一個(gè)抽象類,該類實(shí)現(xiàn)了Runnable接口,,所以按照前面的介紹,,該類具備多線程的能力。 在這種實(shí)現(xiàn)方式中,,通過(guò)繼承TimerTask使該類獲得多線程的能力,,將需要多線程執(zhí)行的代碼書(shū)寫(xiě)在run方法內(nèi)部,然后通過(guò)Timer類啟動(dòng)線程的執(zhí)行,。 在實(shí)際使用時(shí),,一個(gè)Timer可以啟動(dòng)任意多個(gè)TimerTask實(shí)現(xiàn)的線程,但是多個(gè)線程之間會(huì)存在阻塞,。所以如果多個(gè)線程之間如果需要完全獨(dú)立運(yùn)行的話,,最好還是一個(gè)Timer啟動(dòng)一個(gè)TimerTask實(shí)現(xiàn)。 使用該種實(shí)現(xiàn)方式實(shí)現(xiàn)的多線程示例代碼如下: import java.util.*; /** * 測(cè)試類 */ public class Test3 { public static void main(String[] args) { //創(chuàng)建Timer Timer t = new Timer(); //創(chuàng)建TimerTask MyTimerTask mtt1 = new MyTimerTask("線程1:"); //啟動(dòng)線程 t.schedule(mtt1, 0); } } import java.util.TimerTask; /** * 以繼承TimerTask類的方式實(shí)現(xiàn)多線程 */ public class MyTimerTask extends TimerTask { String s; public MyTimerTask(String s){ this.s = s; }
public void run() { try{ for(int i = 0;i < 10;i++){ Thread.sleep(1000); System.out.println(s + i); } }catch(Exception e){} } } 在該示例中,,MyTimerTask類實(shí)現(xiàn)了多線程,,以多線程方式執(zhí)行的代碼書(shū)寫(xiě)在該類的run方法內(nèi)部,該類的功能和前面的多線程的代碼實(shí)現(xiàn)類似,。 而在該代碼中,,啟動(dòng)線程時(shí)需要首先創(chuàng)建一個(gè)Timer類的對(duì)象,以及一個(gè)MyTimerTask線程類的兌現(xiàn),然后使用Timer對(duì)象的schedule方法實(shí)現(xiàn),,啟動(dòng)線程的代碼為: //創(chuàng)建Timer Timer t = new Timer(); //創(chuàng)建TimerTask MyTimerTask mtt1 = new MyTimerTask("線程1:"); //啟動(dòng)線程 t.schedule(mtt1, 0); 其中schedule方法中的第一個(gè)參數(shù)mtt1代表需要啟動(dòng)的線程對(duì)象,,而第二個(gè)參數(shù)0則代表延遲0毫秒啟動(dòng)該線程,也就是立刻啟動(dòng),。 由于schedule方法比較重要,,下面詳細(xì)介紹一下Timer類中的四個(gè)schedule方法: 1、 public void schedule(TimerTask task,Date time) 該方法的作用是在到達(dá)time指定的時(shí)間或已經(jīng)超過(guò)該時(shí)間時(shí)執(zhí)行線程task,。例如假設(shè)t是Timer對(duì)象,,task是需要啟動(dòng)的TimerTask線程對(duì)象,后續(xù)示例也采用這種約定實(shí)現(xiàn),,則啟動(dòng)線程的示例代碼如下: Date d = new Date(2009-1900,10-1,1,10,0,0); t. schedule(task,d); 則該示例代碼的作用是在時(shí)間達(dá)到d指定的時(shí)間或超過(guò)該時(shí)間(例如2009年10月2號(hào))時(shí),,啟動(dòng)線程task。 2,、 public void schedule(TimerTask task, Date firstTime, long period) 該方法的作用是在時(shí)間到達(dá)firstTime開(kāi)始,,每隔period毫秒就啟動(dòng)一次task指定的線程。示例代碼如下: Date d = new Date(2009-1900,10-1,1,10,0,0); t. schedule(task,d,20000); 該示例代碼的作用是當(dāng)時(shí)間達(dá)到或超過(guò)d指定的時(shí)間以后,,每隔20000毫秒就啟動(dòng)一次線程task,,這種方式會(huì)重復(fù)觸發(fā)線程。 3,、 public void schedule(TimerTask task,long delay) 該方法和第一個(gè)方法類似,,作用是在執(zhí)行schedule方法以后delay毫秒以后啟動(dòng)線程task。示例代碼如下: t. schedule(task,1000); 該示例代碼的作用是在執(zhí)行該行啟動(dòng)代碼1000毫秒以后啟動(dòng)一次線程task,。 4,、 public void schedule(TimerTask task,long delay,long period) 該方法和第二個(gè)方法類似,作用是在執(zhí)行schedule方法以后delay毫秒以后啟動(dòng)線程task,,然后每隔period毫秒重復(fù)啟動(dòng)線程task,。 例外需要說(shuō)明的是Timer類中啟動(dòng)線程還包含兩個(gè)scheduleAtFixedRate方法,這兩個(gè)方法的參數(shù)和上面的第二個(gè)和第四個(gè)一致,,其作用是實(shí)現(xiàn)重復(fù)啟動(dòng)線程時(shí)的精確延時(shí),。對(duì)于schedule方法來(lái)說(shuō),如果重復(fù)的時(shí)間間隔是1000毫秒,,則實(shí)際的延遲時(shí)間是1000毫秒加上系統(tǒng)執(zhí)行時(shí)消耗的時(shí)間,,例如為5毫秒,則實(shí)際每輪的時(shí)間間隔為1005毫秒,。而對(duì)于scheduleAtFixedRate方法來(lái)說(shuō),,如果設(shè)置的重復(fù)時(shí)間間隔為1000毫秒,系統(tǒng)執(zhí)行時(shí)消耗的時(shí)間為5毫秒,,則延遲時(shí)間就會(huì)變成995毫秒,,從而保證每輪間隔為1000毫秒。 介紹完了schedule方法以后,,讓我們?cè)賮?lái)看一下前面的示例代碼,,如果在測(cè)試類中啟動(dòng)兩個(gè)MyTimerTask線程,一種實(shí)現(xiàn)的代碼為: import java.util.Timer; /** * 測(cè)試類 */ public class Test4 { public static void main(String[] args) { //創(chuàng)建Timer Timer t = new Timer(); //創(chuàng)建TimerTask MyTimerTask mtt1 = new MyTimerTask("線程1:"); MyTimerTask mtt2 = new MyTimerTask("線程2:"); //啟動(dòng)線程 System.out.println("開(kāi)始啟動(dòng)"); t.schedule(mtt1, 1000); System.out.println("啟動(dòng)線程1"); t.schedule(mtt2, 1000); System.out.println("啟動(dòng)線程2"); } } 在該示例代碼中,,使用一個(gè)Timer對(duì)象t依次啟動(dòng)了兩個(gè)MyTimerTask類型的對(duì)象mtt1和mtt2,。而程序的執(zhí)行結(jié)果是: 開(kāi)始啟動(dòng) 啟動(dòng)線程1 啟動(dòng)線程2 線程1:0 線程1:1 線程1:2 線程1:3 線程1:4 線程1:5 線程1:6 線程1:7 線程1:8 線程1:9 線程2:0 線程2:1 線程2:2 線程2:3 線程2:4 線程2:5 線程2:6 線程2:7 線程2:8 線程2:9 從程序的執(zhí)行結(jié)果可以看出,在Test4類中mtt1和mtt2都被啟動(dòng),,按照前面的schedule方法介紹,,這兩個(gè)線程均會(huì)在線程啟動(dòng)以后1000毫秒后獲得執(zhí)行。但是從實(shí)際執(zhí)行效果卻可以看出這兩個(gè)線程不是同時(shí)執(zhí)行的,,而是依次執(zhí)行,,這主要是因?yàn)橐粋€(gè)Timer啟動(dòng)的多個(gè)TimerTask之間會(huì)存在影響,當(dāng)上一個(gè)線程未執(zhí)行完成時(shí),,會(huì)阻塞后續(xù)線程的執(zhí)行,,所以當(dāng)線程1執(zhí)行完成以后線程2才獲得了執(zhí)行。 如果需要線程1和線程2獲得同時(shí)執(zhí)行,,則只需要分別使用兩個(gè)Timer啟動(dòng)TimerTask線程即可,,啟動(dòng)的示例代碼如下: import java.util.Timer; /** * 測(cè)試類 */ public class Test5 { public static void main(String[] args) { //創(chuàng)建Timer Timer t1 = new Timer(); Timer t2 = new Timer(); //創(chuàng)建TimerTask MyTimerTask mtt1 = new MyTimerTask("線程1:"); MyTimerTask mtt2 = new MyTimerTask("線程2:"); //啟動(dòng)線程 System.out.println("開(kāi)始啟動(dòng)"); t1.schedule(mtt1, 1000); System.out.println("啟動(dòng)線程1"); t2.schedule(mtt2, 1000); System.out.println("啟動(dòng)線程2"); } } 在該示例中,分別使用兩個(gè)Timer對(duì)象t1和t2,,啟動(dòng)兩個(gè)TimerTask線程對(duì)象mtt1和mtt2,,兩者之間不互相干擾,所以達(dá)到了同時(shí)執(zhí)行的目的,。 在使用上面的示例進(jìn)行運(yùn)行時(shí),,由于Timer自身的線程沒(méi)有結(jié)束,所以在程序輸出完成以后程序還沒(méi)有結(jié)束,,需要手動(dòng)結(jié)束程序的執(zhí)行,。例如在Eclipse中可以點(diǎn)擊控制臺(tái)上面的紅色“Teminate”按鈕結(jié)束程序。 12.2.4 小結(jié)關(guān)于線程的三種實(shí)現(xiàn)方式,,就簡(jiǎn)單的介紹這么多,。其實(shí)無(wú)論那種實(shí)現(xiàn)方式,都可以實(shí)現(xiàn)多線程,,在語(yǔ)法允許的前提下,,可以使用任何一種方式實(shí)現(xiàn)。比較而言,,實(shí)現(xiàn)Runnable接口方式要通用一些,。 只是從語(yǔ)法角度介紹線程的實(shí)現(xiàn)方式,還是無(wú)法體會(huì)到線程實(shí)現(xiàn)的奧妙,,下面將通過(guò)幾個(gè)簡(jiǎn)單的示例來(lái)體會(huì)線程功能的強(qiáng)大,,并體會(huì)并發(fā)編程的神奇,從而能夠進(jìn)入并發(fā)編程的領(lǐng)域發(fā)揮技術(shù)的優(yōu)勢(shì)。 posted on 2009-06-15 13:21 找個(gè)美女做老婆 閱讀(7763) 評(píng)論(0) 編輯 收藏 |
|