java中實作多線程操作有兩種手段,一種繼承自Thread類,另一種是實作Runnable接口。
一、繼承Thread
Thread類是在java.lang包中定義的,一個類隻要繼承了Thread類,此類就稱為多線程實作類。在Thread子類中,必須明确地覆寫Thread類中的run()方法,此方法為線程的主體。 [java] view plaincopy <span style="font-size:18px;"> class MyThread extends Thread{ // 繼承Thread類,作為線程的實作類 private String name ; // 表示線程的名稱 public MyThread(String name){ this.name = name ; // 通過構造方法配置name屬性 } public void run(){ // 覆寫run()方法,作為線程 的操作主體 for(int i=0;i<10;i++){ System.out.println(name + "運作,i = " + i) ; } } public class ThreadDemo01{ public static void main(String args[]){ MyThread mt1 = new MyThread("線程A ") ; // 執行個體化對象 MyThread mt2 = new MyThread("線程B ") ; // 執行個體化對象 mt1.run() ; // 調用線程主體 mt2.run() ; // 調用線程主體 } }</span>
二、實作Runnable接口,Runnable接口中隻定義了,一個抽象方法。
class MyThread implements Runnable{ // 實作Runnable接口,作為線程的實作類
private String name ; // 表示線程的名稱
public MyThread(String name){
this.name = name ; // 通過構造方法配置name屬性
public void run(){ // 覆寫run()方法,作為線程 的操作主體
for(int i=0;i<10;i++){
System.out.println(name + "運作,i = " + i) ;
}
public class RunnableDemo01{
public static void main(String args[]){
MyThread mt1 = new MyThread("線程A ") ; // 執行個體化對象
MyThread mt2 = new MyThread("線程B ") ; // 執行個體化對象
Thread t1 = new Thread(mt1) ; // 執行個體化Thread類對象
Thread t2 = new Thread(mt2) ; // 執行個體化Thread類對象
t1.start() ; // 啟動多線程
t2.start() ; // 啟動多線程
三、線程間通信: 多個線程在操作同一個資源,但是操作的動作不同。等待喚醒機制:
<span style="font-size:18px;">class Apple { String name; String color; boolean flag = false; } class Input implements Runnable private Apple r ; Input(Apple r) { this.r = r; public void run() int x = 0; while(true) { synchronized(r) { if(r.flag) //标志位,如果flag=true,那麼說明已經有資料,線程等待 try{r.wait();}catch(Exception e){} if(x==0) { r.name="a"; r.color="red"; } else r.name="b"; r.color = "yellow"; x = (x+1)%2; r.flag = true;//修改标志位 r.notify();//喚醒輸出線程 class Output implements Runnable Output(Apple r) if(!r.flag)//如果線程的标志位flag=false,線程等待 System.out.println(r.name+"...."+r.color); r.flag = false; r.notify();//喚醒輸入線程 class InputOutputTest public static void main(String[] args) Apple r = new Apple(); Input in = new Input(r); Output out = new Output(r); Thread t1 = new Thread(in); Thread t2 = new Thread(out); t1.start(); t2.start();
總結:
wait();notify();notifyALL();
都使用在同步中,因為隻有對持有螢幕(鎖)的線程操作。是以要使用在同步中個,因為隻有同步才具有鎖
為什麼這些操作線程餓方法要定義Object類中呢?因為這些方法在操作同步線程時,都必須要辨別他們所操作的線程隻有的鎖。隻有在同一個鎖上的被等待線程,可以被同一個鎖notify喚醒。不可以對不同鎖中的線程進行喚醒。也就說,等待和喚醒必須是同一個鎖。而鎖可以使任意對象個,是以可以被任意對象調用的方法定義object類中。
終止線程隻有一種,run方法結束。開啟多線程運作,運作代碼通常是循環結構。隻要控制住循環,就可以讓run方法結束,也就是線程結束。特殊情況:當線程處于了當機狀态。就不會讀取到标記。那麼線程就不會結束。當沒有指定的方式讓當機的線程恢複到運作狀态是,這時需要對當機進行清除。強制讓線程恢複到運作狀态中來。這樣就可以操作标記讓線程結束。Thread類提供該方法 interrupt();
四、關于run()和start()分析:
<span style="font-size:18px;">class MyThread extends Thread{ public void run(){ try { Thread.currentThread().sleep(3000); } catch (InterruptedException e) { System.out.println("MyThread running"); public class ThreadTest{ public static void main(String argv[]) { MyThread t = new MyThread(); t.run(); t.start(); System.out.println("Thread Test"); }
代碼分析過程:MyThread t = new MyThread();建立了一個線程。
t.run();調用MyThread對象的run方法。這是隻有一個線程在運作就是主線程。當主線程執行到了run方法中的sleep(3000);時。這是主線程處于當機狀态。程式并沒有任何執行。當3秒過後,主線程列印了 MyThread running。 run方法執行結束。
t.start();開啟了t線程。有兩種可能情況。
第一種,主線程在隻執行了t.start()後,還具有執行權,繼續往下執行,列印了Thread Test。主線程結束。
t線程擷取執行權,調用自己的run方法。然後執行的sleep(3000);當機3秒。3秒後,列印MyThread running t線程結束,整個程式結束。
第二種,主線程執行到t.start();開啟了t線程,t線程就直接擷取到了執行權。就調用自己的run方法。指定到sleep(3000).t線程當機3秒,這是t線程就是釋放了執行權。那麼主線程開始執行列印了Thread Test,主線程結束。
等到3秒後,t線程列印MyThread running ,然後t線程結束。程式結束。