Java中通过Runnable与Thread创建线程的区别

Posted javartisan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中通过Runnable与Thread创建线程的区别相关的知识,希望对你有一定的参考价值。

1 、Java中的Thread与Runnable

1:在Java并发模型中,Thread是跟操作系统底层的线程一对一对应的,Thread对应一个真实的操作系统线程。

2:Runnable只是一个线程执行代码片段的接口标准之外,其余跟线程关系根本不是很大(可以理解:Runnable是一个线程的Task抽象)。Runnable可以理解为线程执行代码的一个单元(juc中Callable也是一个接口标准,可以结合线程池使用,使得线程执行代码,Callable跟Runnable的定义标准有差别:Callable中重写call方法,之外还可以有返回值以及允许跑出异常)。

为什么说Runnable是Thread执行代码的标准呢?

public
class Thread implements Runnable 
    
    private Runnable target;
    
    /* Make sure registerNatives is the first thing <clinit> does. */
    private static native void registerNatives();

    static 
        registerNatives();
    

    @Override
    public void run() 
        //默认实现
        if (target != null) 
            target.run();
        
    
    //忽略代码

Thread实现了Runnable接口,当我们通过继承Thread创建线程时,需要重写run方法,将自己需要执行逻辑放到run中即可;这也就指定标准,用户如何实现线程执行的代码片段。(马士兵说过:一流公司卖标准,标准定义好之后你们按照标准随你们便玩;JDK定义标准,用户按照标准用户随便用)。这也正是创建线程的一种方式。

除此之外而另一种创建是实现Runnable接口,之后将Runnable通过构造器传到Thread中,之后线程启动调用Thread的默认run实现运行任务呢,默认run实现如上代码。

备注:还有一种线程运行代码片段的方法是线程池+Callable实现。

2、两种方式有什么区别?

(一)

1:继承的方式最好之处就是定制,私人定制。例如你去餐厅吃饭,每次都点套餐吃,日子久了你厌倦了,想换个吃法,此时你的吃法餐厅没有现成的套餐可以满足你,此时怎么办?那就是定制,跟老板沟通你的需求,进行私人订制。

class TimeCostThread extends Thread 
    public TimeCostThread(Runnable r) 
        super(r);
    
    @Override
    public void run() 
        System.out.println("start at = " + LocalDate.now());
        super.run();
        System.out.println("start at = " + LocalDate.now());
    

例如,业务需要对任何线程执行的任务都需要记录耗时,此时你可以在你的Task中进行记录耗时,但是假如你有千百个分散不同处时候修改Task很麻烦,此时你就可以自定一个线程满足你的需要。所以继承Thread方式更好的是满足定制需求。

除此之外,

2:创建时资源占,Thread里面有很多局部变量,而Runnable没有。:

3:继承Thread,会将业务代码耦合在Thread中,没有Runnable清晰。

(二)

实现Runnable方式创建线程更多是实现接口由于继承吧(单继承限制)。

1:至于网友说的:实现Runnable的方式代码片段可以共享给多个Thread执行的问题,其实继承Thread也是可以的,因此Thread是Runnable子类,例如:

    public static void main(String[] args) 
        TimeCostThread t = new TimeCostThread(new Runnable() 
            @Override
            public void run() 
                try 
                    Thread.sleep(1000);
                 catch (InterruptedException e) 
                    e.printStackTrace();
                
                System.out.println("task finish!");
            
        );

        new Thread(t).start();
    

但是这种方式由于Thread成员变量以及安全等,比较耗费资源。

2:Thread有局部变量,创建Thread需要初始化局部变量。

3:Runnable比较干净,而且业务代码没有耦合在Thread中

 

(三)个人总结:

1:如果无需定制Thread默认行为,而仅仅是修改run方法行为的话,还是建议使用Runnable方式,使用实现接口方式更优雅。

2:如果有定制化需求的话,则进行继承Thread进行制定。

3:如果代码需要多次执行,推荐Runnable方式共享给执行线程,这种方式比较节约资源,并且启动速度快;Thread会差一些。

 

 

以上是关于Java中通过Runnable与Thread创建线程的区别的主要内容,如果未能解决你的问题,请参考以下文章

JAVA多线程继承Thread 与实现Runnable接口的相关疑问

Java多线程中Thread与Runnable的区别

java 创建线程的三种方法Callable,Runnable,Thread比较及用法

JAVA 线程与线程池简单小结

Java中实现多线程继承Thread类与实现Runnable接口的区别

Thread 和 Runnable