java線程-Thread和Runnable的區別,-threadrunnable
進程:每個進程都有獨立的代碼和資料空間(進程上下文),進程間的切換會有較大的開銷,一個進程包含1--n個線程。
線程:同一類線程共用代碼和資料空間,每個線程有獨立的運行棧和程式計數器(PC),線程切換開銷小。
線程和進程一樣分為五個階段:建立、就緒、運行、阻塞、終止。
多進程是指作業系統能同時運行多個任務(程式)。
多線程是指在同一程式中有多個順序流在執行
在java中要想實現多線程,有兩種手段,一種是繼續Thread類,另外一種是實現Runable介面。
Thread類是在java.lang包中定義的。一個類只要繼承了Thread類同時覆寫了本類中的run()方法就可以實現多線程操作了,但是一個類只能繼承一個父類,這是此方法的局限。一、多線程建立方式Thread&Runnable分別類比賣火車票1、thread方式
class MyThread extends Thread{ private int ticketsCont=5; //一共有5張火車票 private String name; //視窗, 也即是線程的名字 public MyThread(String name){ this.name=name; } @Override public void run(){ while(ticketsCont>0){ ticketsCont--; //如果還有票,就賣掉一張票 System.out.println(name+"賣掉了1張票,剩餘票數為:"+ticketsCont); } }}public class TicketsThread{ public static void main(String args[]){ //建立三個線程,類比三個視窗賣票 MyThread mt1=new MyThread("視窗1"); MyThread mt2=new MyThread("視窗2"); MyThread mt3=new MyThread("視窗3"); //啟動三個線程,也即是視窗,開始賣票 mt1.start(); mt2.start(); mt3.start(); }}
這樣程式可以正常完成互動式運行。那麼為啥非要使用start();方法啟動多線程呢?
在JDK的安裝路徑下,src.zip是全部的java來源程式,通過此代碼找到Thread中的start()方法的定義,可以發現此方法中使用了private native void start0();其中native關鍵字表示可以叫用作業系統的底層函數,那麼這樣的技術成為JNI技術(java Native Interface)。2、Runnable方式
步驟:
1,定義類實現Runnable介面
2,覆蓋Runnable介面中的run方法
將線程要啟動並執行代碼存放在該run方法中
3,通過Thread 類建立線程對象
4,將Runnable介面的子類對象作為實際參數傳遞給Thread類的建構函式
為什麼要將Runnable介面中的子類對象傳遞給Thread的建構函式
因為,自訂的run方法所屬的對象是Runnable介面的子類對象
所以要讓線程去指定指定對象的run方法,就必須明確該run方法所屬對象。
5,調用Thread類的start方法 開啟線程並調用Runnable介面子類的run方法
class MyThread2 implements Runnable{ private int ticketsCont=5; //一共有5張火車票 @Override public void run(){ while(true){ synchronized(this){ if(ticketsCont<=0){ break; } ticketsCont--; //如果還有票,就賣掉一張票 System.out.println(Thread.currentThread().getName()+"賣掉了1張票,剩餘票數為:"+ticketsCont); /*try{ Thread.sleep(50); //通過阻塞程式來查看效果 } catch(Exception e){ System.out.println(e); }*/ } } }}public class TicketsRunnable{ public static void main(String args[]){ MyThread2 mt=new MyThread2(); //建立三個線程來類比三個售票視窗 Thread th1=new Thread(mt,"視窗1"); Thread th2=new Thread(mt,"視窗2"); Thread th3=new Thread(mt,"視窗3"); //啟動三個線程,也即是三個視窗,開始賣票 th1.start(); th2.start(); th3.start(); }}
但是在使用Runnable定義的子類中沒有start()方法,只有Thread類中才有。此時觀察Thread類,有一個構造方法:public Thread(Runnable targer)此構造方法接受Runnable的子類執行個體,也就是說可以通過Thread類來啟動Runnable實現的多線程。(start()可以協調系統的資源):二、總結
- 建立:建立一個線程對象,如Thread thd=new Thread()
- 就緒:建立了線程對象後,調用了線程的start()方法(此時線程知識進入了線程隊列,等待擷取CPU服務 ,具備了啟動並執行條件,但並不一定已經開始運行了)
- 運行:處於就緒狀態的線程,一旦擷取了CPU資源,便進入到運行狀態,開始執行run()方法裡面的邏輯
- 終止:線程的run()方法執行完畢,或者線程調用了stop()方法,線程便進入終止狀態
- 阻塞:一個正在執行的線程在某些情況系,由於某種原因而暫時讓出了CPU資源,暫停了自己的執行,便進入了阻塞狀態,如調用了sleep()方法
在基於線程實現的多線程上(例子1),則總共開闢了三個視窗,在每個視窗賣了5張票,總共賣了15張票,無法實現資源共用,造成程式出錯。
在基於Runnable是,利用同步共用,實現資源共用,則三個視窗總共賣了5張票。
建議使用Runnable這種方式建立線程。 程式中的同一資源指的是同一個Runnable對象。安全的賣票程式中需要加入同步synchronized。
參考文獻
1、JAVA多線程Thread VS Runnable詳解
2、Java中Runnable和Thread的區別