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类完成:


    class MyThread extends Thread{  
        private int ticket=10;  
        public void run(){  
            for(int i=0;i<20;i++){  
                if(this.ticket>0){  
                    System.out.println("卖票:ticket"+this.ticket--);  
                }  
            }  
        }  
    }; 

下面通过三个线程对象,同时卖票:


public class ThreadTicket {  
    public static void main(String[] args) {  
        MyThread mt1=new MyThread();  
        MyThread mt2=new MyThread();  
        MyThread mt3=new MyThread();  
        mt1.start();//每个线程都各卖了10张,共卖了30张票  
        mt2.start();//但实际只有10张票,每个线程都卖自己的票  
        mt3.start();//没有达到资源共享  
    }  
} 

如果用Runnable就可以实现资源共享,下面看例子:

package org.demo.runnable;  
class MyThread implements Runnable{  
    private int ticket=10;  
    public void run(){  
        for(int i=0;i<20;i++){  
            if(this.ticket>0){  
                System.out.println("卖票:ticket"+this.ticket--);  
            }  
        }  
    }  
}  

public class RunnableTicket {  
    public static void main(String[] args) {  
        MyThread mt=new MyThread();  
        new Thread(mt).start();//同一个mt,但是在Thread中就不可以,如果用同一  
        new Thread(mt).start();//个实例化对象mt,就会出现异常  
        new Thread(mt).start();  
    }  
}; 

虽然现在程序中有三个线程,但是一共卖了10张票,也就是说使用Runnable实现多线程可以达到资源共享目的。

 

说法2

Thread类

//代码的运行结果与代码执行顺序或调用顺序是无关的
package ThreadAndRunnable;

public class MyThread extends Thread{

    public MyThread(){
        super();
        System.out.println("当前线程的名字="+Thread.currentThread().getName());
    }
    @Override
    public void run(){

        System.out.println("当前线程的名字="+Thread.currentThread().getName());
    }


package ThreadAndRunnable;

public class Run {

    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        myThread.start();
        System.out.println("运行结束!");
    }
}

(2)运行结果
当前线程的名字=main
运行结束!
当前线程的名字=Thread-0

(3)解释说明
 main函数执行这个MyThread myThread=new MyThread();方法的时候,然后是直接调用MyThread()的构造方法,然后打印出“当前线程的名字=main”,后面先运行结束,然后在打印出Thread线程的run方法,也说明了代码的运行结果与代码的执行顺序或调用顺序是无关的。
Runnable

package Runnable;

public class myrunnable implements Runnable {
    @Override
    public void  run(){
        System.out.println("运行中!");
    }
}

package Runnable;

public class Run {
    public static void main(String[] args) {
        Runnable runnable=new myrunnable();
        Thread thread=new Thread(runnable);
        thread.start();
        System.out.println("运行结束!");
    }
}

(2)运行结果
运行结束!
运行中!

(3)解释说明
Thread类中包括构造函数Thread(Runnable target)和Thread(Runnable target,String name),可以创建Runnable接口,说明构造函数支持传入一个Runnable接口的对象。
下面的图说明了。构造函数Thread(Runnable target)不光可以传入Runnable接口的对象,还可以传入一个Thread类的对象。这样的好处是可以完全将Thread对象中的run()方法交由其他线程进行调用。

 三、比较
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
main函数,实例化线程对象也有所不同,
extends Thread :t.start();
implements Runnable : new Thread(t).start();
使用Runnable,增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类
 

为什么Java 允许实现多接口,却不允许多继承(C++允许)?

如果多继承,会出现语义不明。类c同时继承A,B,AB都有fun()方法,调用c.fun() 会不清楚究竟是调用谁的。

多接口呢?如果类c同时实现接口A,B ,而接口中的都是抽象方法();调用方法时不会出现不明确,毕竟接口中的都是抽象方法,而且 超类 ??的任何方法都需要在子类中覆盖而实现。所以调用接口的方法时,其实是调用自身。


public interface A {  
    void fun();  
}

public interface B {  
    void fun();  
} 

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();  
    }  
}  

 

参考链接

https://blog.csdn.net/dfshsdr/article/details/92432519