Java线程详解(2)-创建与启动
一、定義線程
1、擴展java.lang.Thread類。
????????此類中有個run()方法,應該注意其用法:public void run()
????????如果該線程是使用獨立的Runnable運行對象構造的,則調用該Runnable對象的run方法;否則,該方法不執行任何操作并返回。
????????Thread的子類應該重寫該方法。
2、實現java.lang.Runnable接口。
????????void run()
????????使用實現接口Runnable的對象創建一個線程時,啟動該線程將導致在獨立執行的線程中調用對象的run方法。
????????方法run的常規協定是,它可能執行任何所需的操作。
?
二、實例化線程
? ? ? ? 1、如果是擴展java.lang.Thread類的線程,則直接new即可。
????????2、如果是實現了java.lang.Runnable接口的類,則用Thread的構造方法:
Thread(Runnabletarget)?? Thread(Runnabletarget,?String?name)?? Thread(ThreadGroupgroup,?Runnable?target)?? Thread(ThreadGroupgroup,?Runnable?target,?String?name)?? Thread(ThreadGroupgroup,?Runnable?target,?String?name,?long?stackSize)??? ? ? ? 其中:
????????Runnable target:實現了Runnable接口的類的實例。?
- Thread類也實現了Runnable接口,因此,從Thread類繼承的類的實例也可以作為target傳入這個構造方法。
- 直接實現Runnable接口類的實例。
- 線程池建立多線程。
????????String name:線程的名子。這個名子可以在建立Thread實例后通過Thread類的setName方法設置。默認線程名:Thread-N,N是線程建立的順序,是一個不重復的正整數。
????????ThreadGroup group:當前建立的線程所屬的線程組。如果不指定線程組,所有的線程都被加到一個默認的線程組中。
????????long stackSize:線程棧的大小,這個值一般是CPU頁面的整數倍。如x86的頁面大小是4KB.在x86平臺下,默認的線程棧大小是12KB。
?
三、啟動線程
? ? ? ? 在線程的Thread對象上調用start()方法,而不是run()或者別的方法。
????????在調用start()方法之前:線程處于新狀態中,新狀態指有一個Thread對象,但還沒有一個真正的線程。
????????在調用start()方法之后:發生了一系列復雜的事情——
????????啟動新的執行線程(具有新的調用棧);
????????該線程從新狀態轉移到可運行狀態;
????????當該線程獲得機會執行時,其目標run()方法將運行。
????????注意:對Java來說,run()方法沒有任何特別之處。像main()方法一樣,它只是新線程知道調用的方法名稱(和簽名)。因此,在Runnable上或者Thread上調用run方法是合法的。但并不啟動新的線程。
?
四、例子
? ? ? ? 1、實現Runnable接口的多線程例子
/**?*?實現Runnable接口的類?*/?? public?class?RunnableImpl?implements?Runnable{??private?Stringname;??public?RunnableImpl(String?name)?{??this.name?=?name;??}??@Override??public?void?run()?{??for?(int?i?=?0;?i?<?5;?i++)?{??for(long?k=0;k<100000000;k++);??System.out.println(name+":"+i);??}???????}?? }??/**?*?測試Runnable類實現的多線程程序?*/?? public?class?TestRunnable?{??public?static?void?main(String[]?args)?{??RunnableImpl?ri1=new?RunnableImpl("李白");??RunnableImpl?ri2=new?RunnableImpl("屈原");??Thread?t1=new?Thread(ri1);??Thread?t2=new?Thread(ri2);??t1.start();??t2.start();??}?? }??????????執行結果:
屈原:0?? 李白:0?? 屈原:1?? 李白:1?? 屈原:2?? 李白:2?? 李白:3?? 屈原:3?? 李白:4?? 屈原:4??
????????2、擴展Thread類實現的多線程例子
????????執行結果:
????????對于上面的多線程程序代碼來說,輸出的結果是不確定的。其中的一條語句for(long?k=0;k<100000000;k++);是用來模擬一個非常耗時的操作的。
?
五、一些常見問題
? ? ? ? 1、線程的名字,一個運行中的線程總是有名字的,名字有兩個來源,一個是虛擬機自己給的名字,一個是你自己的定的名字。在沒有指定線程名字的情況下,虛擬機總會為線程指定名字,并且主線程的名字總是mian,非主線程的名字不確定。
????????2、線程都可以設置名字,也可以獲取線程的名字,連主線程也不例外。
????????3、獲取當前線程的對象的方法是:Thread.currentThread();
????????4、在上面的代碼中,只能保證:每個線程都將啟動,每個線程都將運行直到完成。一系列線程以某種順序啟動并不意味著將按該順序執行。對于任何一組啟動的線程來說,調度程序不能保證其執行次序,持續時間也無法保證。
????????5、當線程目標run()方法結束時該線程完成。
????????6、一旦線程啟動,它就永遠不能再重新啟動。只有一個新的線程可以被啟動,并且只能一次。一個可運行的線程或死線程可以被重新啟動。
????????7、線程的調度是JVM的一部分,在一個CPU的機器上上,實際上一次只能運行一個線程。一次只有一個線程棧執行。JVM線程調度程序決定實際運行哪個處于可運行狀態的線程。
????????眾多可運行線程中的某一個會被選中做為當前線程。可運行線程被選擇運行的順序是沒有保障的。
????????8、盡管通常采用隊列形式,但這是沒有保障的。隊列形式是指當一個線程完成“一輪”時,它移到可運行隊列的尾部等待,直到它最終排隊到該隊列的前端為止,它才能被再次選中。事實上,我們把它稱為可運行池而不是一個可運行隊列,目的是幫助認識線程并不都是以某種有保障的順序排列而成一個一個隊列的事實。
????????9、盡管我們沒有無法控制線程調度程序,但可以通過別的方式來影響線程調度的方式。
?
總結
以上是生活随笔為你收集整理的Java线程详解(2)-创建与启动的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java线程详解(1)-概念与原理
- 下一篇: Java线程详解(3)-线程栈模型与线程