Java创建线程的方式详解


创建线程的三种方式

通过Thread创建线程

代码如下:

public static void main(String[] args) {
        // 使用匿名子类的方法创建Thread子类对象(也可以创建一个类继承自Thread类 然后重写run方法来实现)
        Thread thread1 = new Thread() {
            @Override
            public void run() {
                log.debug("hahah");
            }
        };
        thread1.setName("myThread 1");
        thread1.start();
        log.debug("heheh");

        //使用内部类的方法创建Thread子类对象
        //以下代码完全等价与上面
        class MyThread extends Thread{
            @Override
            public void run() {
                log.debug("hahah");
            }
        }
        Thread thread2 = new MyThread();
        thread2.setName("myThread 2");
        thread2.start();
        log.debug("heheh");
}

通过Ruuable接口创建线程

  1. Runnable接口源码
@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

Runnable接口是一个函数式接口,所谓函数式接口就是只包含一个抽象方法的接口

  1. 函数式接口可以通过lambda简化

  2. 代码如下

public class Case2 {
    public static void main(String[] args) {
        // 通过匿名类的方式 创建 实现Runnable接口的 对象
        Runnable runnable = new Runnable() {
            public void run() {
                log.debug("Runnable run() haha");
            }
        };
        // 创建线程
        Thread thread1 = new Thread(runnable, "myThread 1");
        // 运行
        thread1.start();
        // 主线程中的方法
        log.debug("Case2 hehe");

        // 可以使用lambda简化上述代码 (功能完全一样)
        // 创建对象
//        Runnable runnable2 = () -> log.debug("haha lambda");
        // 创建线程
//        Thread thread2 = new Thread(runnable2, "myThread 2");
        // 运行
//        thread2.start();
        // 主线程中的方法
//        log.debug("Case2 hehe");

    }
}

Runnable创建线程的本质

new Thread(runnable, "myThread 1”); 构造方法源码如下

public Thread(Runnable target, String name) {
	init(null, target, name, 0);
}

init源码如下

private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null, true);
}

核心this.target = target;

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

在这里会判断targer是否为空,若不为空则run()调用的是target的方法,也就是调用了Runnable接口实现的方法。(而使用Thread的方式则对run方法进行了重写,直接使用了重写后的run方法)故以上两种方法的本质是相同的。

两种方式的对比分析

  1. Thread是把线程和任务合并在了一起
  2. Runnable是把线程和任务分开了,用 Runnable 更容易与线程池等高级 API 配合
  3. 用 Runnable 让任务类脱离了 Thread 继承体系,更灵活

通过FutureTask创建线程

FutureTask 能够接收 Callable 类型的参数,用来处理有返回结果的情况

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

FutureTask的源码

public class FutureTask<V> implements RunnableFuture<V>

RunnableFuture的源码

public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

创建线程的代码如下

public class Case3 {
    public static void main(String[] args) throws Exception{
        FutureTask<Integer> ft = new FutureTask<Integer>(() -> {
            log.debug("future call haha");
            TimeUnit.SECONDS.sleep(2);
            return 10086;
        });
        Thread ft_thread = new Thread(ft, "ft thread");
        ft_thread.start();
        log.debug("hehe");
        // ft.get()会阻塞运行 直到得到返回结果
        log.debug("{}",ft.get());
    }
}

文章作者: Bxan
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Bxan !
  目录