黑马程序员技术交流社区

标题: 实现多线程的两种方式,区别和好处有哪些 [打印本页]

作者: 欧阳超    时间: 2011-10-8 14:20
标题: 实现多线程的两种方式,区别和好处有哪些
实现多线程的两种方式,区别和好处有哪些
作者: 林国锋    时间: 2011-10-8 14:39
本帖最后由 林国锋 于 2011-10-8 14:44 编辑

一种是扩展java.lang.Thread类
另一种是实现java.lang.Runnable接口

区别就是:第一种是扩展,第二种是实现
好处就是:
在实际开发中通常以实现Runnable接口为主,因为实现Runnable接口相比继承Thread类可以避免继承的局限,一个类可以继承多个接口,适合于资源的共享。

以卖票程序为例,通过Thread类完成:
package org.demo.dff;
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--);
            }
        }
    }
};
下面通过三个线程对象,同时卖票:
package org.demo.dff;
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--);
            }
        }
    }
}
package org.demo.runnable;
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实现多线程可以达到资源共享目的。

Runnable接口和Thread之间的联系:
public class Thread extends Object implements Runnable
发现Thread类也是Runnable接口的子类。
作者: 宁超    时间: 2011-10-8 15:11
楼上说的不错。{:soso_e113:}
其实实现Runnable接口相对于继承Thread类来说,

(1)适合多个相同程序代码的线程去处理同一资源的情况,把虚拟CPU(线程)同程序的代码,数据有效的分离,较好地体现了面向对象的设计思想。
(2)可以避免由于Java的单继承特性带来的局限。我们经常碰到这样一种情况,即当我们要将已经继承了某一个类的子类放入多线程中,由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,那么,这个类就只能采用实现Runnable接口的方式了。
(3)有利于程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。当多个线程的执行代码来自同一个类的实例时,即称它们共享相同的代码。多个线程操作相同的数据,与它们的代码无关。当共享访问相同的对象是,即它们共享相同的数据。当线程被构造时,需要的代码和数据通过一个对象作为构造函数实参传递进去,这个对象就是一个实现了Runnable接口的类的实例。


作者: zhousaowen    时间: 2011-10-8 15:25
本帖最后由 zhousaowen 于 2011-10-8 15:30 编辑

还有一种jdk1.5线程并发库,线程池:
Executors,查看jdk文档就能看到有很多的方法,可以得到一个线程池。
你只要把任务交个线程池,就可以了。新技术,很强悍。
public static void main(String[] args) {
                // TODO Auto-generated method stub
        ExecutorService pool=Executors.newCachedThreadPool(); //构造线程池
        for(int i=0;i<10;i++){
                final int taskid=i;
        pool.execute(new Runnable(){//把任务交给线程池

                        @Override
                        public void run() {
                                // TODO Auto-generated method stub
                                for(int i=0;i<10;i++){
                                        System.out.println(Thread.currentThread().getName()+
                                                        "is execute task "+ taskid+"for"+i
                                                        +"times !");
                                       
                                }
                        }
               
        });
        }
            pool.shutdown();
        }
作者: 成杰    时间: 2011-10-8 16:09
一种从Thread类继承,一种实现Runnable接口,一般用后者。
作者: 黄治文    时间: 2011-10-8 17:07
一种是子类继承Thread类,子类调用start()方法开启一条线程;另一种是实现Runnable接口,但是Runnable接口是没有start()方法的,仍需要用到Thread实例对象调用start()方法开启线程,对比而言,实际开发基本都是用实现Runnable接口,因为继承父类,就局限了扩展性能,而且子类继承Thread类,子类的实例对象是唯一的,在多线程中要满足子类内部数据共享只能用静态数据,由于Thread(Runnable target) 构造方法接受一个Runnable接口实现类,一个Runnable接口实现类里的run()方法可以由多个线程启用,非常容易达到数据共享
作者: 王家俊    时间: 2011-10-9 00:04
Thread是类,Runnable是接口,创建线程这两中方法都可以。但由于接口具有扩展功能,你在实现一个接口的同时又可以继承其他类,也就是说接口可以多继承而类只可以但继承,所有我们一般选择接口。所有这里就选择实现Runnable接口来创建线程了。例如类A实现Runnable的同时还可以继承一个XXX类来创建线程类,这就让他的功能更强大了,但若类A继承Thread类来创建线程的话他就不可以继承XXX类了,这就降低了他的功能。
作者: lucky_xingxing    时间: 2011-10-9 08:44
{:soso_e179:}




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2