美文网首页
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