3.1 创建和运行线程
方法一,直接使用 Thread
// 创建线程对象
Thread t = new Thread() {public void run() {// 要执行的任务}
};
// 启动线程
t.start();
例如:
// 构造方法的参数是给线程指定名字,推荐
Thread t1 = new Thread("t1") {@Override// run 方法内实现了要执行的任务public void run() {log.debug("hello");}
};
t1.start();
输出:
19:19:00 [t1] c.ThreadStarter - hello
方法二,使用 Runnable 配合 Thread
把【线程】和【任务】(要执行的代码)分开
-
Thread 代表线程
-
Runnable 可运行的任务(线程要执行的代码)
Runnable runnable = new Runnable() {public void run(){// 要执行的任务}
};
// 创建线程对象
Thread t = new Thread( runnable );
// 启动线程
t.start();
例如:
// 创建任务对象
Runnable task2 = new Runnable() {@Overridepublic void run() {log.debug("hello");}
};
// 参数1 是任务对象; 参数2 是线程名字,推荐
Thread t2 = new Thread(task2, "t2");
t2.start();
输出:
9:19:00 [t2] c.ThreadStarter - hello
Java 8 以后可以使用 lambda 精简代码
// 创建任务对象
Runnable task2 = () -> log.debug("hello");
// 参数1 是任务对象; 参数2 是线程名字,推荐
Thread t2 = new Thread(task2, "t2");
t2.start();
Thread 与 Runnable 的关系
分析 Thread 的源码,理清它与 Runnable 的关系
//Runnable源码
public interface Runnable {public abstract void run();
}
//Thread源码(部分)
public class Thread implements Runnable {/* What will be run. */private Runnable target;public Thread(Runnable target) {init(null, target, "Thread-" + nextThreadNum(), 0);}private void init(ThreadGroup g, Runnable target, String name,long stackSize, AccessControlContext acc,boolean inheritThreadLocals) {//...this.target = target;//...}@Overridepublic void run() {if (target != null) {target.run();}}
小结
-
方法1 是把线程和任务合并在了一起,方法2 是把线程和任务分开了
-
用 Runnable 更容易与线程池等高级API 配合
-
用 Runnable 让任务类脱离了 Thread 继承体系,更灵活
方法三,FutureTask 配合 Thread
FutureTask 能够接收 Callable 类型的参数,用来处理有返回结果的情况
// 创建任务对象
FutureTask<Integer> task3 = new FutureTask<>(() -> {log.debug("hello");return 100;
});
// 参数1 是任务对象; 参数2 是线程名字,推荐
new Thread(task3, "t3").start();
// 主线程阻塞,同步等待 task 执行完毕的结果
Integer result = task3.get();
log.debug("结果是:{}", result);
输出
19:22:27 [t3] c.ThreadStarter - hello
19:22:27 [main] c.ThreadStarter - 结果是:100
源码分析
//FutureTask源码(部分)
public class FutureTask<V> implements RunnableFuture<V> {/** The underlying callable; nulled out after running */private Callable<V> callable;/** The result to return or exception to throw from get() */private Object outcome; // non-volatile, protected by state reads/writespublic FutureTask(Callable<V> callable) {if (callable == null)throw new NullPointerException();this.callable = callable;this.state = NEW; // ensure visibility of callable}public void run() {//...try {Callable<V> c = callable;if (c != null && state == NEW) {V result;boolean ran;try {result = c.call();ran = true;} catch (Throwable ex) {result = null;ran = false;setException(ex);}if (ran)set(result);}}//...}protected void set(V v) {if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {outcome = v;UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final statefinishCompletion();}}public V get() throws InterruptedException, ExecutionException {int s = state;if (s <= COMPLETING)s = awaitDone(false, 0L);return report(s);}private V report(int s) throws ExecutionException {Object x = outcome;if (s == NORMAL)return (V)x;if (s >= CANCELLED)throw new CancellationException();throw new ExecutionException((Throwable)x);}
}
//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内置了一个Callable对象,初始化方法将指定的Callable赋给这个对象。
-
FutureTask实现了Runnable接口,并重写了Run方法,在Run方法中调用了Callable中的call方法,并将返回值赋值给outcome变量
-
get方法就是取出outcome的值。