美文网首页
Java线程系列——线程的创建

Java线程系列——线程的创建

作者: 禺沫 | 来源:发表于2020-02-21 21:11 被阅读0次

一、线程的创建与对比

关于Java多线程的创建,Oracle文档中是如此描述的:

  1. 一种是将类声明为Thread的子类。该子类应该重写类的run方法Thread。然后可以分配和启动子类的实例。
class PrimeThread extends Thread {
        long minPrime;
        PrimeThread(long minPrime) {
            this.minPrime = minPrime;
        }
        public void run() {
            // compute primes larger than minPrime
             . . .
        }
  }
  1. 另一种方法是声明实现类Runnable接口。然后实现了run方法。然后可以分配类的实例,在创建时作为参数传递Thread,并启动。
class PrimeRun implements Runnable {
         long minPrime;
         PrimeRun(long minPrime) {
             this.minPrime = minPrime;
         }

         public void run() {
             // compute primes larger than minPrime
              . . .
         }
 }

那么这两种方法,哪一种更好呢?可从三个方面考虑:

  1. 基于Java本身只可实现单继承,如果此时使用继承Thread的写法,后续需求更改,需要继承其他类时,变更复杂,而选择实现Runnable接口会更为灵活。
  2. 从代码架构和解耦的角度来说,Runnable只实现具体的任务,功能比较单一,它可以和线程的生命周期分离解耦。
  3. 从资源开销方面来讲,每次新建Thread,均需要创建、执行、销毁,开销是比较大的。而用Runnable还可以选择用线程池等,大大减少创建、销毁线程的损耗。

由此看来,用Runnable会更方便些。

二、两种创建方式的源码解析:

当我们同时使用两种方法创建时,例如下列方式

public class BothRunnableThread {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("我来自Runnable");
            }
        }){
            @Override
            public void run() {
                //super.run();
                System.out.println("我来自Thread");
            }
        }.start();
    }
}

其运行结果是:我来自Thread。看其源码,究其原因:
Thread中的run()方法:

@Override
public void run() {
    if (target != null) {
        target.run();
    }
}

其实是在执行target的run方法,而target呢?Thread中的定义如下:

private Runnable target;

此target是创建Thread时传入的Runnable对象。
可见,如果没有override Thread中的run方法,执行的就是target的run方法,也就是Runnable中的run方法,打印为“我来自Runnable”。但Thread重写了run方法,就不会执行上面三条语句,亦不会判断target对象。而是直接执行了Thread中被override run方法,所以打印出的是"我来自Thread"。

三、一些其他的外在表现形式

以下一些方式,其本质上都是上面两种创建方式的封装:

  1. 线程池创建线,本质上也是用Thread来创建线程
public class ThreadPool {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for(int i = 0; i< 1000; i++){
            executorService.submit(new Task());
        }
    }
}

class Task implements Runnable{
    @Override
    public void run() {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName());
    }
}
  1. 通过Callable和FutureTask创建线程,实质上是实现了Runnable接口
  2. 定时器,和线程池并没有分别

相关文章

网友评论

      本文标题:Java线程系列——线程的创建

      本文链接:https://www.haomeiwen.com/subject/ejwzfhtx.html