一、定義線程
1、擴展java.lang.Thread類。
此類中有個run()方法,應該注意其用法:
public void
run()
如果該線程是使用獨立的
Runnable
運行對象構造的,則調用該
Runnable
對象的
run
方法;否則,該方法不執行任何操作并返回。
Thread
的子類應該重寫該方法。
2、實現java.lang.Runnable接口。
void
run()
使用實現接口
Runnable
的對象創建一個線程時,啟動該線程將導致在獨立執行的線程中調用對象的
run
方法。
二、實例化線程
1 Thread類實例化
直接new即可
2 Runnable實例化
需要用Thread的構造函數實例化
Thread(Runnable target)
Thread(Runnable target, String name)
Thread(ThreadGroup group, Runnable target)
Thread(ThreadGroup group, Runnable target, String name)
Thread(ThreadGroup group, Runnable target, String name, long stackSize)
是個簡單的多線程程序。run()和start()是大家都很熟悉的兩個方法。把希望并行處理的代碼都放在run()中;start()用于自動調用
run(),這是JAVA的內在機制規定的。并且run()的訪問控制符必須是public,返回值必須是void(這種說法不準確,run()沒有返回
值),run()不帶參數。
三、實例化代碼
Thread實例化線程
public class FirstThread extends Thread{
int count= 1, number;
public static int x=1;
FirstThread(int number){
this.number=number;
System.out.println("create thread"+number);
}
public void run(){
// x=x+1;
while(true) {
// System.out.println("create thread"+x);
System.out.println("線程 "+number+":計數 "+count);
if(++count==6)return;
}
}
public static void main(String[] args){
for(int i = 0;i< 5; i++) new FirstThread(i+1).start();
}
}
輸出:(每次輸出不同,可見先建立的線程并不是先執行,比較混亂)
create thread1
create thread2
create thread3
線程 1:計數 1
線程 1:計數 2
create thread4
線程 1:計數 3
線程 2:計數 1
線程 1:計數 4
線程 2:計數 2
線程 2:計數 3
線程 2:計數 4
線程 2:計數 5
線程 3:計數 1
線程 3:計數 2
線程 3:計數 3
create thread5
線程 3:計數 4
線程 4:計數 1
線程 4:計數 2
線程 4:計數 3
線程 4:計數 4
線程 4:計數 5
線程 3:計數 5
線程 1:計數 5
線程 5:計數 1
線程 5:計數 2
線程 5:計數 3
線程 5:計數 4
線程 5:計數 5
Runnable實例化代碼
如果類繼承了別的類,就不能繼承 Thread 了,就要實現 Runnable 接口了
public class FirstRunnale implements Runnable{
int number,count;
FirstRunnale(int number){
this.number=number;
System.out.println("create thread"+number);
}
public void run(){
while(true) {
// System.out.println("create thread"+x);
System.out.println("線程 "+number+":計數 "+count);
if(++count==6)return;
}
}
public static void main(String[] args){
for(int i=0;i<5;i++){
new Thread(new FirstRunnale(i+1)).start();
}
}
}
三、啟動線程
在線程的Thread對象上調用start()方法,而不是run()或者別的方法。
在調用start()方法之前:線程處于新狀態中,新狀態指有一個Thread對象,但還沒有一個真正的線程。
在調用start()方法之后:發生了一系列復雜的事情
啟動新的執行線程(具有新的調用棧);
該線程從新狀態轉移到可運行狀態;
當該線程獲得機會執行時,其目標run()方法將運行。
注意:對Java來說,run()方法沒有任何特別之處。像main()方法一樣,它只是新線程知道調用的方法名稱(和簽名)。因此,在Runnable上或者Thread上調用run方法是合法的。但并不啟動新的線程。
四、補充說明
1、線程的名字,一個運行中的線程總是有名字的,名字有兩個來源,一個是虛擬機自己給的名字,
一個是你自己的定的名字。在沒有指定線程名字的情況下,虛擬機總會為線程指定名字,并且主線
程的名字總是mian,非主線程的名字不確定。
2、線程都可以設置名字,也可以獲取線程的名字,連主線程也不例外。
3、獲取當前線程的對象的方法是:Thread.currentThread();
4、在上面的代碼中,只能保證:每個線程都將啟動,每個線程都將運行直到完成。一系列線程以某
種順序啟動并不意味著將按該順序執行。對于任何一組啟動的線程來說,調度程序不能保證其執行
次序,持續時間也無法保證。
5、當線程目標run()方法結束時該線程完成。
6、一旦線程啟動,它就永遠不能再重新啟動。只有一個新的線程可以被啟動,并且只能一次。一個
可運行的線程或死線程可以被重新啟動。
7、線程的調度是JVM的一部分,在一個CPU的機器上上,實際上一次只能運行一個線程。一次只有一
個線程棧執行。JVM線程調度程序決定實際運行哪個處于可運行狀態的線程。
眾多可運行線程中的某一個會被選中做為當前線程。可運行線程被選擇運行的順序是沒有保障的。
8、盡管通常采用隊列形式,但這是沒有保障的。隊列形式是指當一個線程完成“一輪”時,它移到
可運行隊列的尾部等待,直到它最終排隊到該隊列的前端為止,它才能被再次選中。事實上,我們
把它稱為可運行池而不是一個可運行隊列,目的是幫助認識線程并不都是以某種有保障的順序排列
唱呢個一個隊列的事實。
9、盡管我們沒有無法控制線程調度程序,但可以通過別的方式來影響線程調度的方式。