1. 程式人生 > >再次理解java多執行緒的實現 Thread 和Runnable的區別

再次理解java多執行緒的實現 Thread 和Runnable的區別

Thread和Runnable的區別

如果一個類繼承Thread,則不適合資源共享。但是如果實現了Runable介面的話,則很容易的實現資源共享。

main函式,例項化執行緒物件也有所不同,

extends Thread :t.start();

implements Runnable : new Thread(t).start();

總結:

實現implements Runnable介面比繼承 extends   Thread類所具有的優勢:

1):適合多個相同的程式程式碼的執行緒去處理同一個資源

2):可以避免java中的單繼承的限制(不能訪問父類的私有成員?)

3):增加程式的健壯性,程式碼可以被多個執行緒共享,程式碼和資料獨立

4):執行緒池只能放入實現Runable或callable類執行緒,不能直接放入繼承Thread的類

為什麼這麼說類繼承Thread,則不適合資源共享。但是如果實現了Runable介面的話,則很容易的實現資源共享:舉個賣票的例子:

以賣票程式為例,通過Thread類完成:

  1. package org.demo.dff;  
  2. class MyThread extends Thread{  
  3. privateint ticket=10;  
  4. publicvoid run(){  
  5. for(int i=0;i<20;i++){  
  6. if(this.ticket>0){  
  7. System.out.println("賣票:ticket"
    +this.ticket--);  
  8. }  
  9. }  
  10. }  
  11. }; 

下面通過三個執行緒物件,同時賣票:

  1. package org.demo.dff;  
  2. publicclass ThreadTicket {  
  3. publicstaticvoid main(String[] args) {  
  4. MyThread mt1=new MyThread();  
  5. MyThread mt2=new MyThread();  
  6. MyThread mt3=new MyThread();  
  7. mt1.start();//每個執行緒都各賣了10張,共賣了30張票
  8. mt2.start();//但實際只有10張票,每個執行緒都賣自己的票
  9. mt3.start();
    //沒有達到資源共享
  10. }  

如果用Runnable就可以實現資源共享,下面看例子:

  1. package org.demo.runnable;  
  2. class MyThread implements Runnable{  
  3. privateint ticket=10;  
  4. publicvoid run(){  
  5. for(int i=0;i<20;i++){  
  6. if(this.ticket>0){  
  7. System.out.println("賣票:ticket"+this.ticket--);  
  8. }  
  9. }  
  10. }  
  11. }  
  12. package org.demo.runnable;  
  13. publicclass RunnableTicket {  
  14. publicstaticvoid main(String[] args) {  
  15. MyThread mt=new MyThread();  
  16. new Thread(mt).start();//同一個mt,但是在Thread中就不可以,如果用同一
  17. new Thread(mt).start();//個例項化物件mt,就會出現異常
  18. new Thread(mt).start();  
  19. }  
  20. }; 

雖然現在程式中有三個執行緒,但是一共賣了10張票,也就是說使用Runnable實現多執行緒可以達到資源共享目的。

為什麼Java 允許實現多介面,卻不允許多繼承(C++允許)?

如果多繼承,會出現語義不明。類c同時繼承A,B,AB都有fun()方法,呼叫c.fun() 會不清楚究竟是呼叫誰的。

多介面呢?如果類c同時實現介面A,B ,而介面中的都是抽象方法();呼叫方法時不會出現不明確,畢竟介面中的都是抽象方法,而且 超類 ??的任何方法都需要在子類中覆蓋而實現。所以呼叫介面的方法時,其實是呼叫自身。

package com.whr.demo;  
public interface A {  
    void fun();  
} 
 
package com.whr.demo;   
public interface B {  
    void fun();  
}  
package com.whr.demo;    
public class Demo implements A,B {    
    @Override  
    public void fun() {  
        System.out.println("我自己來實現介面中的抽象方法");  //繼承介面A,B。但是方法的具體實現是自己本函式實現的。接口裡面都是抽象方法。
    }     
    public static void main(String[] args) {  
        Demo demo = new Demo();  
        demo.fun();  
    }  
}  

這裡就要再說一下 介面 和 抽象類的關係了:(之前一直沒有總結)

看到上面,直到為什麼介面可以被多實現,因為->裡面的方法全部是抽象的!什麼是抽象?就是final static 不能被呼叫,只能被override?

介面:比抽象類更抽象。是物件  動作的抽象。描述物件能做什麼。介面中方法常用一些,成員變數用得少一些。

1.裡面所有的方法都是抽象abstract的,沒有任何實現,所有可變的東西都應該歸屬到實現類中Runnable()介面的run()方法,很明顯體現。(start方法是Thread的);;;介面中的方法必須是public 的,要可以被重寫,不然繼承接口乾什麼。

2.介面中的成員變數只有一種型別,public static final ,所以可以直接省去修飾符。

 -----------public  。保證所有實現類的共有。

-----------static :所有實現類都只有這一份,避免重名。如果實現類的第二個介面也同名,那麼儲存時候就會報錯(是好事)。

-----------既然抽象類,肯定final,大家都用的,不能隨便改。否則違反設計模式的OCP開閉原則->穩定靈活的系統。

3.不含構造器。

[修飾符] interface 介面名 [extends 父介面名列表]{

[public] [static] [final] 常量;
[public] [abstract] 方法;//沒有方法體
}
public interface CalInterface    {  
    final float PI=3.14159f;//定義用於表示圓周率的常量PI  
    float getArea(float r);//定義一個用於計算面積的方法getArea()  
    float getCircumference(float r);//定義一個用於計算周長的方法getCircumference()  
}
一個類實現多個介面,同名變數的訪問
interface X {
    public static final String name="123";
}
interface Y {
    public static final String name="456";
}
public class Z implements X,Y {
    public static void main (String [] args){
        System.out.println(X.name);//如果不定義為 static 的成員變數,如果實現的兩個介面中有同名變數,則不能引用。
        System.out.println(Y.name); //不能寫做 Z t1 = new Z(); System.out.print(z.name);這時候會報錯,定義為static 就是為了在編譯時就能發現錯誤。
    }
}
/*
 * 執行結果:
 * 123
 * 456
 * */

抽象類:是物件 根源的抽象。本質區別於別的類。描述物件是什麼。

1.裡面的方法,抽象或不抽象方法。抽象方法都放給子類來具體實現。

2.成員變數 可以是static ,也可以普通的成變。

3.可以包含構造器,並不建立物件,而是讓子類可以呼叫構造器完成屬於抽象類的初始化。

抽象類中的功能>>介面。但是訂一起來代價高。而且java單繼承侷限了,得在這個類裡面寫出所有子類的共性。

//抽象類的宣告  
abstract class Animal {  
    String type;  
    String name;  
    int age;  
    int weight;  
    void eat() {  
        System.out.println("動物愛吃飯");  
    }  
    //抽象方法在抽象類中只能宣告,不能具體實現  
    abstract void breath();  
    void sleep() {  
        System.out.println("動物在睡覺");  
    }  
}  
//由子類去繼承父類抽象類  
class tiger extends Animal{    
    @Override  
    //在此處實現抽象方法  breath()
    void breath() {  
        System.out.println("老虎在呼吸");  
    }  
}  
public class first_for {  
    public static void main(String [] args){  
        // 錯誤,程式會報錯  
        //報錯原因:抽象類不能進行例項化操作  
        //Animal Tiger = new Animal();          
        //只能用子類進行例項化  *************66666666666
        Animal Tiger = new tiger();  
        Tiger.breath();  
    }  
}