再次理解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. private int ticket=10;  
  4. public void 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. public class ThreadTicket {  
  3. public static void 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. private int ticket=10;  
  4. public void 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. public class RunnableTicket {  
  14. public static void 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();  
    }  
}  



你可能感兴趣的:(再次理解java多线程的实现 Thread 和Runnable的区别)