A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 宋超2356 中级黑马   /  2014-4-2 20:29  /  985 人查看  /  5 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

有两种方式都可以创建一个线程,具体有什么区别呢(就是不是对于继承和接口区别,而是对于这两种方式创建的线程的方式,分别用在哪里合适,或者没啥区别?)

  1. public class Test implements Runnable {
  2.        
  3.        
  4.         public static void main(String[] args) {
  5.                 Test td1 = new Test();
  6.                 Thread t1 = new Thread(td1);
  7.                 t1.start();
  8.         }
  9.        
  10.         public void run() {
  11.                 System.out.println("我在运行");
  12.         }
  13. }
复制代码
  1. public class Test extends Thread{
  2.        
  3.         public static void main(String[] args) {
  4.                 Test thread = new Test();
  5.                 thread.start();
  6.         }
  7. }
复制代码



评分

参与人数 1技术分 +1 收起 理由
itpower + 1

查看全部评分

5 个回复

倒序浏览
本帖最后由 2528870651 于 2014-4-2 20:46 编辑

实现Runable方式好处:避免了单继承的局限性。  如果一个类继承了另一个类的话,它还能用extends Thread来创建线程吗??   不可能吧!!!  java不支持多继承,所以这时候就只能用implements Runnable接口来创建线程了。你查看API文档就会发现,其实Thread本身就实现了Runable接口。   
建议你尽量用implements Runable方式来 创建线程。


两种方式区别:
继承Thread:线程代码存放Thread子类run方法中。
实现Runnable,线程代码存在接口的子类的run方法。

评分

参与人数 1技术分 +1 收起 理由
itpower + 1

查看全部评分

回复 使用道具 举报
创建线程实际应用当中都是实现Runnable借口。实现接口还有一个好处就是可以共享一个对象资源。
比如你上面的
  1. public class Test implements Runnable {
  2.         
  3.         
  4.         public static void main(String[] args) {
  5.                 Test td1 = new Test();
  6.                 Thread t1 = new Thread(td1);
  7.                 Thread t2 = new Thread(td1);//td1可以创建两个线程,这也是实现Runnable接口的好处
  8.                 t1.start();
  9.         }
  10.         
  11.         public void run() {
  12.                 System.out.println("我在运行");
  13.         }
  14. }
复制代码

评分

参与人数 1技术分 +1 收起 理由
itpower + 1

查看全部评分

回复 使用道具 举报
使用Runnable更接近于面向对象。因为我们是把任务封装在了Runnable对象的run方法中。我们再把Runnable对象传递给Thread的构造方法。其实就是Thread这个类在指挥Runnable干事情。这就是面向对象的思想。

评分

参与人数 1技术分 +1 收起 理由
itpower + 1

查看全部评分

回复 使用道具 举报
两种方法的联系与区别:
1. 两种方法均需执行线程的start方法为线程分配 必须的系统资源、调度线程运行并执行线程的 run方法。

2. 在具体应用中,采用哪种方法来构造线程体要 视情况而定。通常,当一个线程已继承了另一 个类时,就应该用第二种方法来构造,即实现 Runnable接口

如果你看Thread类的源码就会发现其实:Thread类实现了Runnable,
Runnable target;

/**
     * Calls the <code>run()</code> method of the Runnable object the receiver
     * holds. If no Runnable is set, does nothing.
     *
     * @see Thread#start
     */
    public void run() {
        if (target != null) {
            target.run();
        }
    }
当使用继承Thread类方式来生成线程对象时,我们需要重写 run方法,因为Thread类的run
方法此时什么事情也不做。
当使用实现Runnable方式来生成线程对象时,我们需要实现 Runnable接口的 run方法,然
后使用new Thread(new MyThread())(假如MyThread 已经实现了 Runnable接口)来
生成线程对象,这时的线程对象的 run方法就会调用MyThread类的run方法,这样
我们自己编写的 run方法就执行了。

评分

参与人数 1技术分 +1 收起 理由
itpower + 1

查看全部评分

回复 使用道具 举报
在Java中创建线程有两种方法:继承Thread类和实现Runnable接口。
一、继承Thread类创建线程类(Thread类已经实现了 Runnable接口)
1、Thread类的构造方法有8个,但常用的只有4个,分别为:
Thread类中的两个最主要的方法:
(1)run()—包含线程运行时所执行的代码,即线程需要完成的任务,是线程执行体。
(2)start()—用于启动线程。

2、通过继承Thread类来创建并启动多线程的步骤:
(1)定义Thread类的子类,并覆盖该类的run()方法。
(2)创建Thread子类的实例,即创建线程对象。
(3)用线程对象的start()方法来启动该线程。
例程:
Java 代码
   1. public class Thread1 extends Thread{  
   2.     public void run(){  
   3.         System.out.println(this.getName());  
   4.     }  
   5.     public static void main(String args[]){  
   6.         System.out.println(Thread.currentThread().getName());  
   7.         Thread1 thread1 = new Thread1();  
   8.         Thread1 thread2 = new Thread1();  
   9.         thread1.start();  
  10.         thread2.start();  
  11.     }  
  12. }  

public class Thread1 extends Thread{
    public void run(){
        System.out.println(this.getName());
    }
    public static void main(String args[]){
        System.out.println(Thread.currentThread().getName());
        Thread1 thread1 = new Thread1();
        Thread1 thread2 = new Thread1();
        thread1.start();
        thread2.start();
    }
}
程序的运行结果如下:
main
Thread-0
Thread-1

注意:程序中两条线程并发执行时,每次的执行结果是会变化的。这是因为,如果多个没有同步约束关系的线程并发执行时,调度线程将不能保证哪个线程先执行及其持续的时间,在不同平台上,或在同一平台上不同时刻的多次运行可能会得到不同的结果。
Java中对于线程启动后唯一的能够保障的就是:“每个线程都将启动,每个线程都会执行结束”。但谁会先执行谁会后执行,将没有保障,也就是说,就算一个线程在另一个线程之前启动,也无法保障该线程一定在另一个线程之前执行完毕。

程序分析如下:
(1)任何一个Java程序都必须有一个主线程。主线程的线程执行体不是由run()方法来确定的,而是由main()方法来确定的:main()方法的方法体代表主线程的线程执行体。
(1)上面程序用到线程的两个方法:
Thread.currentThread():currentThread()是Thread类的静态方法,该方法总是返回当前正在执行的线程对象的引用。
getName():该方法是Thread类的实例方法,该方法返回调用该方法的线程的名字。
(3)程序可以通过setName(String name)方法为线程设置名字,也可以通过getName()方法返回指定线程的名字。在默认情况下,主线程的名字为main,用户启动的多条线程的名字依次为:Thread-0、Thread-1、Thread-2、……、Thread-n等。
(4)一个线程只能被启动一次。否则会抛出java.lang.IllegalThreadStateException异常。
二、实现Runnable接口创建线程类

实现Runnable接口的类必须使用Thread类的实例才能创建线程。通过实现Runnable接口来创建并启动多线程的步骤:
(1)定义Runnable接口的实现类,并实现该接口的run()方法。
(2)创建Runnable实现类的实例,然后将该实例作为参数传入Thread类的构造方法来创建Thread对象。
(3)用线程对象的start()方法来启动该线程。
例程:
Java 代码

   1. public class MyRunnable implements Runnable{  
   2.     public void run(){  
   3.         System.out.println(Thread.currentThread().getName());  
   4.     }  
   5.     public static void main(String args[]){  
   6.         MyRunnable r1 = new MyRunnable();  
   7.         MyRunnable r2 = new MyRunnable();  
   8.         MyRunnable r3 = new MyRunnable();  
   9.         Thread thread1 = new Thread(r1,"MyThread1");  
  10.         Thread thread2 = new Thread(r2);  
  11.         thread2.setName("MyThread2");  
  12.         Thread thread3 = new Thread(r3);  
  13.         thread1.start();  
  14.         thread2.start();  
  15.         thread3.start();  
  16.     }  
  17. }  

public class MyRunnable implements Runnable{
    public void run(){
        System.out.println(Thread.currentThread().getName());
    }
    public static void main(String args[]){
        MyRunnable r1 = new MyRunnable();
        MyRunnable r2 = new MyRunnable();
        MyRunnable r3 = new MyRunnable();
        Thread thread1 = new Thread(r1,"MyThread1");
        Thread thread2 = new Thread(r2);
        thread2.setName("MyThread2");
        Thread thread3 = new Thread(r3);
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

三、两种创建线程方式的比较

采用继承Thread类方式:
(1)优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。
(2)缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类。
采用实现Runnable接口方式:
(1)优点:线程类只是实现了Runable接口,还可以继承其他的类。在这种方式下,可以多个线程共享同一个目标(target)对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
(2)缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。

评分

参与人数 1技术分 +1 收起 理由
itpower + 1

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马