创建线程的四种方式以及FutureTask解析
1. 创建线程的四种方式
-
使用Thread创建
-
使用Runnable创建
-
使用Callable创建
-
使用线程池创建
Thread
public static void main(String[] args) {
ThreadInnerDemo innerDemo = new ThreadInnerDemo();
//执行Thread main - end
innerDemo.run();
}
static class ThreadInnerDemo extends Thread{
public void run(){
System.out.printf("执行Thread %s - end",Thread.currentThread().getName());
System.out.println("");
}
}
Runnable
public static void main(String[] args) {
Thread thread = new Thread(new Runnable2());
//执行Thread main - end
thread.run();
}
static class Runnable2 implements Runnable{
@Override
public void run() {
System.out.printf("执行Runnable %s - end ",Thread.currentThread().getName());
System.out.println("");
}
}
Callable
public static void main(String[] args) throws ExecutionException, InterruptedException {
//使用Callable的时候要配合FutureTask或者线程池去使用,下面会介绍FutureTask在中间起了什么作用
Callable2<Integer> callable2 = new Callable2<>();
FutureTask<Integer> ft = new FutureTask<>(callable2);
Thread thread = new Thread(ft);
thread.run();
System.out.println(ft.get());
System.out.println(future.get());
}
static class Callable2<Integer> implements Callable<java.lang.Integer> {
@Override
public java.lang.Integer call() throws Exception {
System.out.printf("执行Runnable %s - end ",Thread.currentThread().getName());
System.out.println("");
return 100;
}
}
线程池创建
public static void main(String[] args) throws ExecutionException, InterruptedException {
//第一种类型,使用线程池去执行FutureTask
Callable2<Integer> callable2 = new Callable2<>();
FutureTask<Integer> ft = new FutureTask<>(callable2);
ExecutorService service = Executors.newFixedThreadPool(1);
service.submit(ft);
System.out.println(ft.get());
service.shutdown();
//第二种直接使用jdk8封装好的CompletableFuture去执行线程,内部也是依赖线程池去执行。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.printf("执行Runnable %s - end ", Thread.currentThread().getName());
System.out.println("");
return "12323";
});
System.out.println(future.get());
}
2. FutureTask解析
- 首先看看一下Futurn的类图,由下可以看出来,FutureTask实现了RunnableFuture接口,而RunnableFuture接口分别继承了Runnable和Future接口。
首先我们分别看一下Runnable和Future接口
@FunctionalInterface
public interface Runnable {
//定义线程执行块的逻辑
public abstract void run();
}
//定义线程运行状态
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;
}
public interface RunnableFuture<V> extends Runnable, Future<V> {
//运行入口
void run();
}
-
接下来我们逐步分析FutureTask的运行过程
//callable2 传入执行的callable代码块 FutureTask<Integer> ft = new FutureTask<>(callable2); //调用构造函数来初始化callable和state状态,其中state代表任务执行的状态 public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; } //除了上面的构造函数之外还有一个对Runnable提供的构造函数 public FutureTask(Runnable runnable, V result) { this.callable = Executors.callable(runnable, result); this.state = NEW; }
//看源码注释中标识了,任务执行状态可能出现的流转情况 /** * Possible state transitions: * NEW -> COMPLETING -> NORMAL 任务执行正常的状态流转 * NEW -> COMPLETING -> EXCEPTIONAL 任务执行异常的状态流转 * NEW -> CANCELLED 取消任务的状态流转 * NEW -> INTERRUPTING -> INTERRUPTED 中断任务的状态流转 */ private static final int NEW = 0; //初始状态。 private static final int COMPLETING = 1; //任务已经执行完成或者执行任务的时候发生异常 private static final int NORMAL = 2;//任务已经执行完成并且任务执行结果已经保存到outcome字段 private static final int EXCEPTIONAL = 3;//任务执行发生异常并且异常原因已经保存到outcome字段中后 private static final int CANCELLED = 4;//任务还没开始执行或者已经开始执行但是还没有执行完成的时候,用户调用了cancel(false)方法取消任务且不中断任务执行线程,这个时候状态会从NEW转化为CANCELLED状态。这是一个最终态。 private static final int INTERRUPTING = 5;//调用了cancel(true)方法取消任务并且要中断任务执行线程但是还没有完全中断任务。(中间态) private static final int INTERRUPTED = 6;//调用interrupt()中断任务执行线程之后状态会从INTERRUPTING转换到INTERRUPTED。
run
/** * obj 需要更新的对象 * obj中整型filed的偏移量 * expect 期望的值 * update 修改的值 */ public final native boolean compareAndSwapObject(Object obj, long offset, Object expect, Object update); public void run() { //1.判断任务状态如果不是初始状态 //2.则执行CSA,如果obj的offset等于null,则更新为当前线程 //runnerOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("runner")); 返回指定静态filed的内存地址和偏移量 if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) return; try { Callable<V> c = callable; if (c != null && state == NEW) { V result; boolean ran; try { //执行callable的call方法 result = c.call(); ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } if (ran) //设置响应结果 set(result); } } finally { //设置runner为null runner = null; int s = state; //判断状态是否为中断,如果是,则执行线程中断逻辑 if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); } } private void handlePossibleCancellationInterrupt(int s) { if (s == INTERRUPTING) while (state == INTERRUPTING) Thread.yield(); // wait out pending interrupt } protected void setException(Throwable t) { //设置状态为执行中 if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) { //设置outcome为异常 outcome = t; //再将stateOffset设置为异常状态 UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state //调用完成方法 finishCompletion(); } }
set
protected void set(V v) {
//将状态NEW更新为COMPLETING
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING))
//将callable的响应值赋值给outcome
outcome = v;
//将stateOffset 更新为NORMAL,设置obj对象的offset偏移地址对应的整型field的值的指定值
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
private void finishCompletion(){
// assert state > COMPLETING;
// waitersOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("waiters"));
//在awaitDone()方法中设置了waiters,此时进到循环中
for (WaitNode q; (q = waiters) != null;) {
//不满足(q = waiters) != null 此条件,所以不进来
if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
for (;;) {
Thread t = q.thread;
if (t != null) {
q.thread = null;
//解锁awaitDone()阻塞的资源
LockSupport.unpark(t);
}
//如果等待子节点为空,则跳出玄幻,执行结束
WaitNode next = q.next;
if (next == null)
break;
q.next = null; // unlink to help gc
q = next;
}
break;
}
}
//空方法,留给子类拓展
done();
callable = null; // to reduce footprint
}
get
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
//如果状态小于或者等于1,则代表是任务初始状态或者正在执行阶段
s = awaitDone(false, 0L);
return report(s);
}
private int awaitDone(boolean timed, long nanos) throws InterruptedException {
//截止时间为0
final long deadline = timed ? System.nanoTime() + nanos : 0L;
WaitNode q = null;
boolean queued = false;
for (;;) {
//while循环,先判断线程是否中断,如果中断则在等待队列中删除该节点并抛出中断异常
if (Thread.interrupted()) {
//等待队列中删除该节点
removeWaiter(q);
throw new InterruptedException();
}
int s = state;
//如果s大于1,代表任务已经结束
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
else if (s == COMPLETING)
//如果状态 = COMPLETING 代表表示任务已经结束但是任务执行线程还没来得及给outcome赋值
//这个时候让出执行权让其他线程优先执行
Thread.yield();
else if (q == null)
//如果等待节点为空,则构造一个等待节点
q = new WaitNode();
else if (!queued)
//如果还没有入队列,则把当前节点加入waiters首节点并替换原来waiters
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
else if (timed) {
// 如果需要等待特定时间,则先计算要等待的时间
// 如果已经超时,则删除对应节点并返回对应的状态
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
removeWaiter(q);
return state;
}
//阻塞等待特定时间
LockSupport.parkNanos(this, nanos);
}
else
//阻塞等待直到被其他线程唤醒,会在执行结束任务后,在finishCompletion()中唤醒次方法
LockSupport.park(this);
}
}
通过打断电发现,执行上面方法的过程中会循环3次,
第一次:发现q == null,创建了q = new WaitNode();
//设置new WaitNode()的next = waiters
第二次:发现!queued,queued = UNSAFE.compareAndSwapObject(this, waitersOffset,q.next = waiters, q);
第三次:LockSupport.park(this);当线程执行完后,唤醒次模块,会走到s > COMPLETING,代表线程执行结束
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);
}