创建线程为何只有一种方式? - Java

创建多线程可以使用下面四种方式:

  • 继承Thread
  • 实现Runnable接口
  • 通过Callable和FutureTask创建线程
  • 通过线程池创建线程

第一印象, 你可能会想到这四种创建线程的方式. 可是其实创建线程只有一种方式, 就是 new Thread()

展示上面所说的四种创建线程的方式:

代码演示

package top.clearlight.blog.hollis.thread;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class CreateThread implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println(Thread.currentThread().getName());

        // 第一种创建方式
        System.out.println("继承Thread类创建的线程");
        Thread t = new SubClassThread();
        t.start();

        // 第二种创建方式
        System.out.println("实现Runnable接口创建线程");
        CreateThread t2 = new CreateThread();
        new Thread(t2).start();

        // 第三种创建方式
        CallableThread callableThread = new CallableThread();
        FutureTask ft = new FutureTask(callableThread);
        new Thread(ft).start();
        // get()方法会阻塞主线程, 一直等子线程执行完成并返回后才能继续执行主线程后面的代码

        int i = 0;
        // isDone判断子线程是否执行完, call方法执行完后, 返回true
        while (!ft.isDone()) {
            // 子线程执行完执行主线程执行其他事情
            System.out.println("main" + i++);
            Thread.sleep(1000);
        }

        System.out.println(ft.get());

        System.out.println("阻塞了3s钟后," + Thread.currentThread().getName() + "继续执行");
    }
}

class SubClassThread extends Thread {
    @Override
    public void run() {
        System.out.println(getName());
    }
}

class CallableThread implements Callable {
    @Override
    public Object call() throws Exception {
        System.out.println(Thread.currentThread().getName());
        Thread.sleep(3000);
        return "Hello Thread";
    }
}

线程池创建线程代码:

package top.clearlight.blog.hollis.thread;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class CreateThreadPool {

    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName());
        System.out.println("通过线程池创建线程");
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10));
       /* threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });*/

        // 通过线程池创建线程
        threadPoolExecutor.execute(() -> System.out.println(Thread.currentThread().getName()));

    }
}


首先, 多线程的状态第一步, NEW(初始化) : 新创建一个线程对象, 但还没调用start()方法.

下面开始讲解为何创建线程的方式本质上只有一种!

首先, 扩展Thread, 实际调用父类Thread类的无参构造函数,

在这里插入图片描述
进入调用四个参数的构造函数

在这里插入图片描述
继续进入(部分代码)
创建线程为何只有一种方式? - Java_第1张图片
因此, 扩展Thread方式其实是调用了Thread类的六个构造参数的构造方法来创建线程.

第二种方式 : 实现Runnable, 通过实现Runnable接口后重写run方法后创建Runnable对象传入接受Runnable接口的构造参数

在这里插入图片描述
在这里插入图片描述

最终还是进入六个参数的构造函数, 只是传入的参数不同, 其实创建线程的方式, 本质都是通过传入不同的参数来调用同一个构造函数.

第三种方式 :

创建线程为何只有一种方式? - Java_第2张图片
在这里插入图片描述
这里发现, 只是传入的target不同.

第四种方式 : 线程池创建线程

在这里插入图片描述

进入execute方法

创建线程为何只有一种方式? - Java_第3张图片

		/*
	 	 *	1.如果正在运行的线程少于corePoolSize线程,请尝试执行以下操作:
         *以给定命令作为第一个线程来启动新线程
         *任务。对addWorker的调用自动检查runState和
         * workerCount,因此可以防止假警报的增加
         *在不应该执行的情况下通过返回false进行线程化。
         *
         * 2.如果任务可以成功排队,那么我们仍然需要
         *仔细检查我们是否应该添加线程
         *(因为现有的自上次检查后死亡)或
         *自从进入此方法以来,该池已关闭。所以我们
         *重新检查状态,并在必要时回退排队
         *停止,如果没有,则启动一个新线程。
         *
         * 3.如果我们无法将任务排队,那么我们尝试添加一个新的
         *线程。如果失败,我们知道我们已经关闭或饱和
         *并因此拒绝任务。
         * /

调用addWorker

创建线程为何只有一种方式? - Java_第4张图片
创建线程为何只有一种方式? - Java_第5张图片
在这里插入图片描述
最终还是通过new Thread方式来创建线程.

对这四种方式进行分析, 可以了解到创建线程的方式其实就只有一种

你可能感兴趣的:(#,Java基础知识)