Java 高级教程系列 - 线程创建

Java Tutorial for Language Adavanced - Create Thread

Posted by zihengCat on 2019-07-14

Java 创建多线程(Multithreading)

Java 并发编程以多线程(Multithreading)为基础。Java 屏蔽了不同操作系统之间多线程 API 的差异,抽象出一套统一的多线程编程范式,为程序员减轻多线程开发的难度。

在 Java 中,线程被抽象为了Thread类,一枚Thread类实例即对应一枚操作系统线程(1:1)。Java 线程创建有如下几种方式:

  • 继承Thread

  • 实现Runnable接口

  • 实现Callable接口

继承Thread

继承Thread类,覆写其run()方法,即可创建线程。

import java.lang.String;
import java.lang.Thread;
public class MyThread extends Thread {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
    }
    @Override
    public void run() {
        for (int i = 0; i < 10; ++i) {
            System.out.println("[INFO]: MyThread -> " + String.valueOf(i));
        }
    }
}

代码清单:继承Thread

实现Runnable接口

直接继承Thread类创建线程,可能会受限于 Java 仅支持单继承的局限性,不够灵活。实现Runnable接口,实现接口run()方法体,是另一种创建线程的方式。在创建线程时,向Thread类构造函数传递一枚Runnable实例。

import java.lang.String;
import java.lang.Runnable;
public class MyRunnable implements Runnable {
    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.start();
    }
    @Override
    public void run() {
        for (int i = 0; i < 10; ++i) {
            System.out.println("[INFO]: MyRunnable -> " + String.valueOf(i));
        }
    }
}

代码清单:实现Runnable接口

Runnable接口非常简单,只有一个待实现的抽象run()方法。

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

代码清单:Runnable接口源码

实现Callable接口

Callable接口的出现是为了弥补Runnable接口实现多线程无法带回线程任务执行结果(返回值),无法抛出异常的局限。利用CallableFutureFutureTask等并发组件,我们可以方便地取得多线程任务的执行结果。

import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.FutureTask;
public class MyCallable implements Callable<String> {
    public static void main(String[] args) {
        FutureTask<String> futureTask = new FutureTask<String>(
            new MyCallable()
        );
        Thread myCallable = new Thread(futureTask);
        myCallable.start();
        try {
            String result = futureTask.get();
            System.out.println("[INFO]: myCallable result -> " + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Override
    public String call() throws Exception {
        for (int i = 0; i < 10; ++i) {
            System.out.println("[INFO]: MyCallable -> " + String.valueOf(i));
        }
        return "MyCallable-" + String.valueOf(this.hashCode());
    }
}

代码清单:实现Callable接口

Callable接口是一枚泛型接口,有一个待实现call()方法。如果线程正常退出,方法可带回线程执行结果,如果线程执行出错,则抛出异常。

@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}

代码清单:Callable接口源码

Future接口是一枚泛型接口,提供了Callable线程任务的一些调用方法,如:获取计算结果、取消线程任务、判断任务是否完成…

public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

代码清单:Future接口源码

Thread类源码观察

我们观察Thread类源码,可以看到,在Thread类构造函数中,Runnable实例会被传递至内部target中,并在线程中实际调用target.run()

...
    /* What will be run. */
    private Runnable target;
...

    /**
     * Initializes a Thread.
     *
     * @param g the Thread group
     * @param target the object whose run() method gets called
     * @param name the name of the new Thread
     * @param stackSize the desired stack size for the new thread, or
     *        zero to indicate that this parameter is to be ignored.
     * @param acc the AccessControlContext to inherit, or
     *            AccessController.getContext() if null
     * @param inheritThreadLocals if {@code true}, inherit initial values for
     *            inheritable thread-locals from the constructing thread
     */
    private Thread(ThreadGroup g, Runnable target, String name,
                   long stackSize, AccessControlContext acc,
                   boolean inheritThreadLocals) {
...
    }
    /**
     * If this thread was constructed using a separate
     * {@code Runnable} run object, then that
     * {@code Runnable} object's {@code run} method is called;
     * otherwise, this method does nothing and returns.
     * <p>
     * Subclasses of {@code Thread} should override this method.
     *
     * @see     #start()
     * @see     #stop()
     * @see     #Thread(ThreadGroup, Runnable, String)
     */
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
...

代码清单:Thread类部分源码

关联文章(Related Topics)

参考资料(References)