【并发编程】你知道哪些实现线程的方法?

面试官经常会问你知道哪些实现线程的方法,这是因为实现线程是并发编程的基础,必须要先会实现线程,才可以继续后续的一系列操作。今天我就来说一下创建线程的常用方法。

用Runnable接口创建线程

/**
 * 用Runnable接口创建线程
 */
public class RunnableThread implements Runnable{
    @Override
    public void run() {
        System.out.println("用Runnable接口实现线程类");
    }
    public static void main(String[] args) throws Exception {
        //用Runnable接口实现线程
        ImplThread.RunnableThread runnableThread = new ImplThread.RunnableThread();
        runnableThread.run();
    }
}

继承Thread类创建线程

//继承Thread类创建线程
public class ExtendsThread extends Thread{
    @Override
    public void run() {
        System.out.println("用Thread类实现线程");
    }
		public static void main(String[] args) throws Exception {
        //继承Thread类实现线程
        ExtendsThread extendsThread = new ExtendsThread();
        extendsThread.run();
    }
}

用线程池创建线程

/**
 *用线程池创建线程
 */
public class RunnableThread implements Runnable{
    @Override
    public void run() {
        System.out.println("用Runnable接口实现线程类");
    }
    public static void main(String[] args) throws Exception {
        //用线程池创建线程
        ExecutorService executorService= Executors.newFixedThreadPool(10);
        executorService.execute(new RunnableThread());
    }
}

实现Callable接口创建线程

//实现Callable接口创建线程
public class CallableTask implements Callable<String>{
    @Override
    public String call() throws Exception {
        return "用Callable接口创建线程";
    }
		public static void main(String[] args) throws Exception {
        //用Callable接口创建线程
        CallableTask callableTask = new CallableTask();
        FutureTask<String> futureTask = new FutureTask<>(callableTask);
        futureTask.run();
        System.out.println(futureTask.get());
    }
}

无论是 Callable 还是 FutureTask,它们首先和 Runnable 一样,都是一个任务,是需要被执行的,而不是说它们本身就是线程。

创建线程的方法只有一种

本质上创建线程只有一种方式,就是构造一个 Thread 类,这是创建线程的唯一方式。因为使用实现 Runnable 接口的方式虽然也可以自定义线程,但 Runnable 实例是并没有 start 方法的。

因此,仍然需要 new 一个 Thread 类的实例,将 Runnable 实例当作参数传递给 Thread 的构造方法,最后同样通过 Thread 实例的 start 方法,让 JVM 来启动线程。

实现线程执行内容的有两种

虽然创建线程只有一种方法,但想要实现线程执行的内容,却有两种方式。可以通过实现 Runnable 接口,或继承 Thread 类重写 run() 方法,把我们想要执行的代码传入,让线程去执行。

实现 Runnable 比继承 Thread更好,你知道为什么吗?

如果不清楚为什么,先看部分Runnable、Thread源码,再思考一下。

Runnable

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

Thread

public class Thread implements Runnable {
    private static native void registerNatives();
    static {
        registerNatives();
    }
    private volatile String name;
    private int            priority;
    private Thread         threadQ;
    private long           eetop;
    private boolean     single_step;
    private boolean     daemon = false;
    private boolean     stillborn = false;
    private Runnable target;
    private ThreadGroup group;
    private ClassLoader contextClassLoader;
    private AccessControlContext inheritedAccessControlContext;
    private static int threadInitNumber;
    private static synchronized int nextThreadNum() {
        return threadInitNumber++;
    }
    ThreadLocal.ThreadLocalMap threadLocals = null;
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
    private long stackSize;
    private long nativeParkEventPointer;
    private long tid;
    private static long threadSeqNumber;
    private volatile int threadStatus = 0;
    private static synchronized long nextThreadID() {
        return ++threadSeqNumber;
    }
    volatile Object parkBlocker;
    private volatile Interruptible blocker;
    private final Object blockerLock = new Object();
    void blockedOn(Interruptible b) {
        synchronized (blockerLock) {
            blocker = b;
        }
    }
    public final static int MIN_PRIORITY = 1;
    public final static int NORM_PRIORITY = 5;
    public final static int MAX_PRIORITY = 10;
    public static native Thread currentThread();
}

相信你已经有答案了,再提供一些我的见解供你参考。

第一点

代码的架构考虑,Runnable 里只有一个 run() 方法,负责定义需要执行的内容,实现了 Runnable 与 Thread 类的解耦。而Thread 类负责线程启动和属性设置等内容,权责分明。

第二点

使用继承 Thread 类方式,每次执行一次任务,都需要新建一个独立的线程,任务执行完后就会被销毁。如果我们使用实现 Runnable 接口的方式,就可以把任务直接传入线程池,使用一些固定的线程来完成任务,不需要每次新建销毁线程,大大降低了性能开销。

第三点

Java 语言不支持多继承,如果我们的类一旦继承了 Thread 类,那么它后续就没有办法再继承其他的类,这样一来,未来这个类需要继承其他类实现一些功能上的拓展,它就没有办法做到了,相当于限制了代码未来的可拓展性。

站在巨人的肩膀上

  • 徐隆曦—《Java并发编程》
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值