`

Java中继承thread类与实现Runnable接口的区别

    博客分类:
  • java
阅读更多

Java中线程的创建有两种方式:

 

1.  通过继承Thread类,重写Threadrun()方法,将线程运行的逻辑放在其中

2.  通过实现Runnable接口,实例化Thread

 

    在实际应用中,我们经常用到多线程,如车站的售票系统,车站的各个售票口相当于各个线程。当我们做这个系统的时候可能会想到两种方式来实现,继承Thread类或实现Runnable接口,现在看一下这两种方式实现的两种结果。


package com.threadtest;
class MyThread extends Thread{
    
    private int ticket = 10;
    private String name;
    public MyThread(String name){
        this.name =name;
    }
    
    public void run(){
        for(int i =0;i<500;i++){
            if(this.ticket>0){
                System.out.println(this.name+"卖票---->"+(this.ticket--));
            }
        }
    }
}
public class ThreadDemo {

    
    public static void main(String[] args) {
        MyThread mt1= new MyThread("一号窗口");
        MyThread mt2= new MyThread("二号窗口");
        MyThread mt3= new MyThread("三号窗口");
        mt1.start();
        mt2.start();
        mt3.start();
    }

}

 

运行结果如下:

一号窗口卖票---->10
一号窗口卖票---->9
二号窗口卖票---->10
一号窗口卖票---->8
一号窗口卖票---->7
一号窗口卖票---->6
三号窗口卖票---->10
一号窗口卖票---->5
一号窗口卖票---->4
一号窗口卖票---->3
一号窗口卖票---->2
一号窗口卖票---->1
二号窗口卖票---->9
二号窗口卖票---->8
三号窗口卖票---->9
三号窗口卖票---->8
三号窗口卖票---->7
三号窗口卖票---->6
三号窗口卖票---->5
三号窗口卖票---->4
三号窗口卖票---->3
三号窗口卖票---->2
三号窗口卖票---->1
二号窗口卖票---->7
二号窗口卖票---->6
二号窗口卖票---->5
二号窗口卖票---->4
二号窗口卖票---->3
二号窗口卖票---->2
二号窗口卖票---->1

 

通过实现Runnable接口的代码如下:
 

package com.threadtest;
class MyThread1 implements Runnable{
    private int ticket =10;
    private String name;
    public void run(){
        for(int i =0;i<500;i++){
            if(this.ticket>0){
                System.out.println(Thread.currentThread().getName()+"卖票---->"+(this.ticket--));
            }
        }
    }
}
public class RunnableDemo {

    
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //设计三个线程
         MyThread1 mt = new MyThread1();
         Thread t1 = new Thread(mt,"一号窗口");
         Thread t2 = new Thread(mt,"二号窗口");
         Thread t3 = new Thread(mt,"三号窗口");
//         MyThread1 mt2 = new MyThread1();
//         MyThread1 mt3 = new MyThread1();
         t1.start();
         t2.start();
         t3.start();
    }

}

 

运行结果如下:

一号窗口卖票---->10
三号窗口卖票---->9
三号窗口卖票---->7
三号窗口卖票---->5
三号窗口卖票---->4
三号窗口卖票---->3
三号窗口卖票---->2
三号窗口卖票---->1
一号窗口卖票---->8
二号窗口卖票---->6

 

 

    为什么会出现这种结果呐。我们不妨做个比喻,其实刚的程序,

继承Thread类的,我们相当于拿出三件事即三个卖票10张的任务分别分给三个窗口,他们各做各的事各卖各的票各完成各的任务,因为MyThread继承Thread类,所以在new MyThread的时候在创建三个对象的同时创建了三个线程;

实现Runnable的, 相当于是拿出一个卖票10张得任务给三个人去共同完成,new MyThread相当于创建一个任务,然后实例化三个Thread,创建三个线程即安排三个窗口去执行。

     

用图表示如下:



 

   在我们刚接触的时候可能会迷糊继承Thread类和实现Runnable接口实现多线程,其实在接触后我们会发现这完全是两个不同的实现多线程,一个是多个线程分别完成自己的任务,一个是多个线程共同完成一个任务

     

    其实在实现一个任务用多个线程来做也可以用继承Thread类来实现只是比较麻烦,一般我们用实现Runnable接口来实现,简洁明了。

      

    大多数情况下,如果只想重写 run() 方法,而不重写其他 Thread 方法,那么应使用 Runnable 接口。这很重要,因为除非程序员打算修改或增强类的基本行为,否则不应为该类(Thread)创建子类。

 

 

 

 

  • 大小: 44 KB
  • 大小: 28.3 KB
分享到:
评论
17 楼 jamin415 2017-02-08  
感觉楼主还没理解透彻,可以先看看源代码这两个类是怎么实现的,Thread是实现了Runable的接口,知道这个就明了了
16 楼 hudazheng 2017-01-04  
mars914 写道
a455642158 写道
非常感谢……对于下面这段代码:
         MyThread1 mt = new MyThread1(); 
         Thread t1 = new Thread(mt,"一号窗口"); 
         Thread t2 = new Thread(mt,"二号窗口"); 
         Thread t3 = new Thread(mt,"三号窗口");
我们老大非常反感,说你这样写是错的,跟我说是在api里面找不到根据。
我也不会解释,哎,无语。

jdk api 里面没有说明,但是可以通过程序的执行来说明,事实。

MyThread1 mt = new MyThread1(); 改成 Runnable mt = new MyThread1();
15 楼 coolcgp 2016-11-16  
博主用继承Thread用new,用Runnable时用共享,概念搞错了,Thread也能共享资源。不过,加油,大家都是这么走过来的。只是希望后来者提醒,仅此而已。
14 楼 Koby丶 2016-07-20  
flight2006 写道
这篇文章举例和结论都没错,但是博主理解有误!
实现Runable的一个好处就是能实现资源共享,结论正确(因为继承Thread实现不了)
但是不是说实现Runable就是实现了资源共享,实际上还是通过
MyThread1 mt = new MyThread1();  

这个对象实现的共享,如果是三个不同对象:
MyThread1 mt1 = new MyThread1(); 
MyThread1 mt2 = new MyThread1(); 
MyThread1 mt2 = new MyThread1(); 
Thread t1 = new Thread(mt1,"一号窗口");  
Thread t2 = new Thread(mt2,"二号窗口");  
Thread t3 = new Thread(mt3,"三号窗口");  


这样执行的结果是和上面完全一样的。

总结一下,实现Runable除了避免单继承的局限外,还有个好处就是能实现不同进程资源共享,而继承Thread没有这个功能。并不是这个特点是两者的绝对区别,继承Runable你可以选择不共享。


Thread也能共享资源,
MyThread mt= new MyThread(); 
Thread t1 = new Thread(mt,"一号窗口");   
Thread t2 = new Thread(mt,"二号窗口");  
Thread t3 = new Thread(mt,"三号窗口");
执行结果和Runnable一样
13 楼 drivedreams 2016-04-07  
MyThread1 mt = new MyThread1(); 
Thread t1 = new Thread(mt,"一号窗口"); 
Thread t2 = new Thread(mt,"二号窗口"); 
Thread t3 = new Thread(mt,"三号窗口");
你这种写法存在很大的问题,t1读取ticket=1,因为是多线程t2也可能在读取ticket=1,
t1对ticket-- ,ticket =0 ,此时t2也对ticket--,因为判断还有票,那么此时的ticket=-1
12 楼 flight2006 2015-08-28  
这篇文章举例和结论都没错,但是博主理解有误!
实现Runable的一个好处就是能实现资源共享,结论正确(因为继承Thread实现不了)
但是不是说实现Runable就是实现了资源共享,实际上还是通过
MyThread1 mt = new MyThread1();  

这个对象实现的共享,如果是三个不同对象:
MyThread1 mt1 = new MyThread1(); 
MyThread1 mt2 = new MyThread1(); 
MyThread1 mt2 = new MyThread1(); 
Thread t1 = new Thread(mt1,"一号窗口");  
Thread t2 = new Thread(mt2,"二号窗口");  
Thread t3 = new Thread(mt3,"三号窗口");  


这样执行的结果是和上面完全一样的。

总结一下,实现Runable除了避免单继承的局限外,还有个好处就是能实现不同进程资源共享,而继承Thread没有这个功能。并不是这个特点是两者的绝对区别,继承Runable你可以选择不共享。
11 楼 best_programmer 2014-10-07  
在世界的中心呼喚愛 写道
这个文章有错。。

MyThread1 mt = new MyThread1();  
         Thread t1 = new Thread(mt,"一号窗口");  
         Thread t2 = new Thread(mt,"二号窗口");  
         Thread t3 = new Thread(mt,"三号窗口");  


这里代码有问题啊,不是Thread和runnable的问题。。这里共享一个资源了。。
其实就是接口和继承的问题。。

 
         Thread t1 = new Thread(new MyThread1(),"一号窗口");  
         Thread t2 = new Thread(new MyThread1(),"二号窗口");  
         Thread t3 = new Thread(new MyThread1(),"三号窗口");  


这样才是ok的。每一个线程一个资源

thanks,明白了。楼主自己把自己讲糊涂了,让我也糊涂了。他的结果出现的原因是因为资源共享,与线程的实现方式并无关······大牛,接着帮忙回答下这个问题呗http://bbs.csdn.net/topics/390889930
10 楼 在世界的中心呼喚愛 2014-09-01  
这个文章有错。。

MyThread1 mt = new MyThread1();  
         Thread t1 = new Thread(mt,"一号窗口");  
         Thread t2 = new Thread(mt,"二号窗口");  
         Thread t3 = new Thread(mt,"三号窗口");  


这里代码有问题啊,不是Thread和runnable的问题。。这里共享一个资源了。。
其实就是接口和继承的问题。。

 
         Thread t1 = new Thread(new MyThread1(),"一号窗口");  
         Thread t2 = new Thread(new MyThread1(),"二号窗口");  
         Thread t3 = new Thread(new MyThread1(),"三号窗口");  


这样才是ok的。每一个线程一个资源
9 楼 luo877280 2014-08-19  
我想说这个 没解决接口和继承的问题   楼主 你看着改了吧!!!
8 楼 learnTECh 2014-07-10  
当extends Thread时,
MyThread mt1= new MyThread("一号窗口"); 
MyThread mt2= new MyThread("二号窗口"); 
MyThread mt3= new MyThread("三号窗口");
创建了3个MyThread对象,分别执行start()方法,每个对象都有自己的ticket=10
如果private static ticket = 10; 就可以实现拥有共同的ticket=10
执行结果就跟实现Runnable一样了


当实现Runnable的时候
MyThread1 mt = new MyThread1(); 
Thread t1 = new Thread(mt,"一号窗口"); 
Thread t2 = new Thread(mt,"二号窗口"); 
Thread t3 = new Thread(mt,"三号窗口");
创建了一个对象,3个进程, 共用一个对象,共同拥有一个ticket=10

这样理解对不对?
7 楼 best_programmer 2014-05-09  
eighteencold 写道
汗,你还是把这篇删了吧,太误人子弟了,这明明是
MyThread1 mt = new MyThread1(); 
Thread t1 = new Thread(mt,"一号窗口"); 
Thread t2 = new Thread(mt,"二号窗口"); 
Thread t3 = new Thread(mt,"三号窗口");

MyThread mt1= new MyThread("一号窗口"); 
MyThread mt2= new MyThread("二号窗口"); 
MyThread mt3= new MyThread("三号窗口"); 
mt1.start(); 
mt2.start(); 
mt3.start(); 
两种写法之间的区别,不要上升到Java中继承thread类与实现Runnable接口的区别好不!

问下这两种写法不是正好对应继承thread类与实现Runnable接口吗?哪儿错了吗?只不过实现Runnable接口平常都是创建匿名对象直接调用start()方法吧
6 楼 eighteencold 2013-11-29  
汗,你还是把这篇删了吧,太误人子弟了,这明明是
MyThread1 mt = new MyThread1(); 
Thread t1 = new Thread(mt,"一号窗口"); 
Thread t2 = new Thread(mt,"二号窗口"); 
Thread t3 = new Thread(mt,"三号窗口");

MyThread mt1= new MyThread("一号窗口"); 
MyThread mt2= new MyThread("二号窗口"); 
MyThread mt3= new MyThread("三号窗口"); 
mt1.start(); 
mt2.start(); 
mt3.start(); 
两种写法之间的区别,不要上升到Java中继承thread类与实现Runnable接口的区别好不!
5 楼 ByteCoder 2013-04-28  
对于第一种写法
引用
MyThread mt1= new MyThread("一号窗口"); 
        MyThread mt2= new MyThread("二号窗口"); 
        MyThread mt3= new MyThread("三号窗口");

由于Thread类本身也实现了Runnable接口,所以上面的写法也可以写成
 MyThread mt= new MyThread();
 Thread t1 = new Thread(mt,"一号窗口");  
 Thread t2 = new Thread(mt,"二号窗口"); 
 Thread t3 = new Thread(mt,"三号窗口"); 

当然这种写法并不好,但足以说明你的想法是错误
对于第二种写法
引用

MyThread1 mt = new MyThread1(); 
Thread t1 = new Thread(mt,"一号窗口"); 
Thread t2 = new Thread(mt,"二号窗口"); 
Thread t3 = new Thread(mt,"三号窗口");

可以改成
引用

Thread t1 = new Thread(new MyThread1(),"一号窗口"); 
Thread t2 = new Thread(new MyThread1(),"二号窗口"); 
Thread t3 = new Thread(new MyThread1(),"三号窗口");

这两种的区别主要还是接口和继承类的区别
4 楼 a455642158 2012-07-20  
mars914 写道
a455642158 写道
非常感谢……对于下面这段代码:
         MyThread1 mt = new MyThread1(); 
         Thread t1 = new Thread(mt,"一号窗口"); 
         Thread t2 = new Thread(mt,"二号窗口"); 
         Thread t3 = new Thread(mt,"三号窗口");
我们老大非常反感,说你这样写是错的,跟我说是在api里面找不到根据。
我也不会解释,哎,无语。

jdk api 里面没有说明,但是可以通过程序的执行来说明,事实。



谢谢 我在jdk api里面找到这种写法了哈……
3 楼 mars914 2012-07-03  
a455642158 写道
非常感谢……对于下面这段代码:
         MyThread1 mt = new MyThread1(); 
         Thread t1 = new Thread(mt,"一号窗口"); 
         Thread t2 = new Thread(mt,"二号窗口"); 
         Thread t3 = new Thread(mt,"三号窗口");
我们老大非常反感,说你这样写是错的,跟我说是在api里面找不到根据。
我也不会解释,哎,无语。

jdk api 里面没有说明,但是可以通过程序的执行来说明,事实。
2 楼 a455642158 2012-07-03  
非常感谢……对于下面这段代码:
         MyThread1 mt = new MyThread1(); 
         Thread t1 = new Thread(mt,"一号窗口"); 
         Thread t2 = new Thread(mt,"二号窗口"); 
         Thread t3 = new Thread(mt,"三号窗口");
我们老大非常反感,说你这样写是错的,跟我说是在api里面找不到根据。
我也不会解释,哎,无语。
1 楼 mars914 2012-05-03  
实现Runnable接口相对于继承Thread类来说,有如下显著的好处:
1.适合多个相同程序代码的线程去处理同一资源的情况,把虚拟CPU(线程)同程序的代码、数据有效分离,较好地体现了面向对象的设计思想。
2.可以避免由于JAVA的单继承特性带来的局限。我们经常碰到这样一种情况,即当我们要将已继承了某一个类的子类放入多线程中,由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,那么,这个类就只能采用实现Runnable接口的方式了。
3.有利于程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。当多个线程的执行代码来自同一个类的实例时,即称它们共享相同的代码。多个线程可以操作相同的数据,与它们的代码无关。当共享访问相同的对象时,即它们共享相同的数据。当线程被构造时,需要的代码和数据通过一个对象作为构造函数实参传递进去,这个对象就是一个实现了Runnable接口的类的实例。
事实上,几乎所有多线程应用都可以用实现Runnable接口的方式。


//上面所说的看得不是很明白,但大致从两个方面分析了两种实现多线程方法的区别,一就是资源共享,二就是java单继承的问题。

-------------------------------------------------------------------------------------

对于具有相同目标对象的线程,当其中一个线程享用CPU资源时,目标对象自动调用接口中的run()方法,这时run()方法中的局部变量被分配内存空间。当轮到另一个线程享用CPU资源时,目标对象会再次调用接口中的run()方法,那么run()方法中的局部变量会再次分配内存空间。也就是说,run()方法已经启动运行了两次,分别运行在不同的线程中,即运行在不同的时间片内。run()方法中的局部变量称为线程的局部变量。不同线程的run()方法中的局部变量互不干扰,一个线程改变了自己的run()方法中局部变量的值,不会影响其他线程的run()方法中的局部变量。

相关推荐

Global site tag (gtag.js) - Google Analytics