天天看點

【多線程】——Thread VS Runnable

程序和線程的關系

    多個線程構成一個程序,線程是程序中的一個元素,例如QQ.exe檢視電腦程序的時候發現隻有一個程序,但是我們可以同時和多個使用者聊天交流,而且可以一邊聊天,刷空間之類。對每一個使用者的聊天就是一個線程,多個使用者的互動構成程序。

    示範一個不使用多線程的Demo,也就是單線程

public class SingleDemo{
  public static void main(String[] args){
    MyThread myThread = new MyThread();
    myThread.run();
    while(true){
      System.out.println("Main方法在運作");
    }
  }
}
  
  class MyThread{
    public void run(){
      while (true){
        System.out.println("MyThread類的run()方法在運作");
      }
    }
  }      

  根據demo可以知道mian中的run方法永遠都不可能被執行

【多線程】——Thread VS Runnable

      一張圖說明何為單線程和多線程!

【多線程】——Thread VS Runnable

 從圖中很清晰表明我們使用多線程的原因

繼承Thread建立多線程

public class DemoThread{
  public static void main(String[] args){
    MyThread myThread = new MyThread();
    myThread.start(); //通過start()開啟了一個新的線程
    while(true){
      System.out.println("run()方法在運作");
    }
  }
}
class MyThread extends Thread {
  public void run(){
    while(true){
      System.out.println("MyThread類的run()方法在運作");
    }
  }
}      

顯示結果

【多線程】——Thread VS Runnable

實作Runnable接口建立多線程

public class DemoRunnable{
  public static void main(String[] args){
    RunnableDemo runnable = new RunnableDemo();
    Thread mythread = new Thread(runnable);
    mythread.start();
    while(true){
      System.out.println("main類的run()方法在運作");
    }
  }
}
class RunnableDemo implements Runnable{
  public void run(){
    while(true){
      System.out.println("RunnableDemo類的run()方法在運作");
    }
  }
}      

顯示結果

【多線程】——Thread VS Runnable

目前實作多線程的方式繼承Thread,另一種實作Runnable接口。

上述Demo是利用Thread(Runnable target)這個構造函數實作的,Runnable是一個接口其中隻有一個run()方法,在調用Thread時,看一下Thread的類結構就知道,其實實作的是接口Runnable中的方法。是以兩種多線程實作方式具有多态關系。

Thread VS Runnable

    先說一個例子,火車站售票會牽扯到一個資源共享的問題,資源就是車票,每個售票都相當與一個線程,假如有100張票,每張票理論上都隻能買一個人,下面看Thread和Runnable的處理方式

繼承Thread

public class DemoExceple{
  public static void main(String[] args){
    new TicketWindow().start();
    new TicketWindow().start();
    new TicketWindow().start();
    new TicketWindow().start();
  }
}
class TicketWindow extends Thread{
    private int tickets = 100;
    public void run(){
      while(true){
        if(tickets>0){
          Thread th = Thread.currentThread();
          String name = th.getName();
          System.out.println(name+"正在發售第"+tickets--+"張票");
        }
      }
    }
  }      

運作結果

【多線程】——Thread VS Runnable

    根據這個運作結果,發現每一張票都被重複賣了四次,明顯這種多線程的方式并不太适合資源共享的問題。

實作Runnable接口

public class RunnableDemoTest{
  public static void main(String[] args){
    TicketWindow tw = new TicketWindow();
    new Thread(tw,"視窗1").start();
    new Thread(tw,"視窗2").start();
    new Thread(tw,"視窗3").start();
    new Thread(tw,"視窗4").start();
  }
  
}
class TicketWindow implements Runnable{
  private int tickets = 100;
  public void run(){
    while(true){
      if(tickets>0){
        Thread th = Thread.currentThread();
        String th_name = th.getName();
        System.out.println(th_name+"正在發售第"+tickets--+"張票");
      }
    }
  }
}      

運作結果

【多線程】——Thread VS Runnable

根據運作結果發現使用Runnable接口剛好能解決我們資源共享的問題。

為什麼Thread不行,而Runnable就可以?

Thread方式中建立了4個Thread對象,4個線程分别執行4個對象中的代碼,是以4個線程是獨立的去完成賣票任務

Runnable方式,同樣建立了4個Thread對象,但是隻有一個Runnable對象,4個Thread對象共享Runnable中的代碼,是以,便會出現4個線程同時完成賣票的任務的結果。如果建立4個Runnable對象,分别做為參數傳入4個Thread中,結果會和Thread方式一樣的。

    其實實作Runnable接口的線程中如果出現休眠,在資源共享也會出現非線程安全的問題,最根本的解決方式資源共享的問題還是同步鎖(synchronized)的機制。

結論

   根據上述兩種情況,其實Runnable和Thread能完成相同的功能,畢竟Thread也是實作Runnable,兩者根本的差別一個是繼承,一個是實作。

1、Runnable相當于一個作業,而Thread才是真正的處理線程。通過new Thread(Runnable target)把作業交給線程去處理,這樣達到松耦合的效果,也是符合面向對象中組合的使用。

繼續閱讀