天天看點

黑馬程式員java筆記之二-----多線程

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線程結束。程式結束。