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会差一些。

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值