java并发基础(一)-创建线程的方法和实践

Thread源码分析

我们可以看到平时我们通过实现Runnable接口和继承Thread来重写run方法,最终归结到了run方法的调用上。一个是重写,一个是调用接口的方法。

源码示例:

/* What will be run. */
    private Runnable target;
		public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
		private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null, true);
    }
		
		private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
        ......
        
        this.target = target;
        
      	......
    }
		@Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

Oracle官方文档对创建线程的说明

  • Java SE 8 API文档:
    docs.oracle.com/javase/8/do…
  • 请查看java.lang.Thread的类说明文档。 a. 将类继承Thread类重写run方法
  • 官方原话:There are two ways to create a new thread of execution. One is to declare a classto be a subclass of Thread. This subclass should override the runmethod of class Thread.

实现多线程的方法

实现多线程的官方正确的只有两种方法,但是显然使用方法1实现的更好

方法1:实现Runnable接口

/**
 * 1.实现runnable接口
 */
public class RunnableStyle implements Runnable {

    public static void main(String[] args) {

        /**
         * 3。调用runnable接口
         */
        RunnableStyle target=new RunnableStyle();
        Thread thread=new Thread(target);
        thread.start();
    }
    /**
     * 2.实现run接口
     */
    @Override
    public void run() {
        log.info("运行了线程-{}",Thread.currentThread().getId());

    }
}

方法2:继承Thread类

public class ThreadStyle extends Thread {

    public static void main(String[] args) {

        /**
         * 调用ThreadStyle和启动
         */
        ThreadStyle threadStyle=new ThreadStyle();
        threadStyle.start();

    }

    /**
     * 2.重写run方法,覆盖父类方法
     */
    @Override
    public void run() {
        log.info("运行了线程-{}",Thread.currentThread().getId());
    }
}

不推荐继承Thread类

继承Thread类是不推荐的,因为它有以下的一些缺点:

  1. 从代码架构角度:具体的任务(run方法)应该和“创建和运行线程的机制(Thread类)”解耦,用runnable对象可以实现解耦。
  2. 使用继承Thread的方式的话,那么每次想新建一个任务,只能新建一个独立的线程,而这样做的损耗会比较大(比如重头开始创建一个线程、执行完毕以后再销毁等。如果线程的实际工作内容,也就是run()函数里只是简单的打印一行文字的话,那么可能线程的实际工作内容还不如损耗来的大)。如果使用Runnable和线程池,就可以大大减小这样的损耗。
  3. 继承Thread类以后,由于Java语言不支持双继承,这样就无法再继承其他的类,限制了可扩展性。

两种方法的本质对比

方法一和方法二,也就是“实现Runnable接口并传入Thread类”和“继承Thread类然后重写run()”在实现多线程的本质上,并没有区别,都是最终调用了start()方法来新建线程。这两个方法的最主要区别在于

run()方法的内容来源:

@Override
public void run() {
    if (target != null) {
        target.run();
    }
}
  • 方法一:最终调用target.run(),(target传入的runnable的run方法);
  • 方法二:run()整个都被重写

start方法的执行流程

  1. 检查线程状态,只有NEW状态下的线程才能继续,否则会抛出IllegalThreadStateException(在运行中或者已结束的线程,都不能再次启动,详见CantStartTwice10类)
  2. 被加入线程组
  3. 调用start0()方法启动线程

注意点:

start方法是被synchronized修饰的方法,可以保证线程安全;
由JVM创建的main方法线程和system组线程,并不会通过start来启动。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值