1. 스레드 작업 구성표 1 생성 : 실행 가능
runnable에는 반환 값이 없으며 run은 스레드 논리를 구현합니다.
public interface Runnable {
public abstract void run();
}
2. 스레드 태스크 프로그램 2 생성 : 호출 가능
2.1 호출 가능
callable에는 반환 값 (V)이 있고 호출은 스레드 논리를 구현합니다.
public interface Callable<V> {
V call() throws Exception;
}
2.2 미래
Callabe는 단독으로 사용할 수 없으며 Callable 실행을 제어하고 Callable 실행 결과를 얻으려면 Future가 필요합니다.
public interface Future<V> {
// 如果任务已经成功了,或已经取消了,是无法再取消的,会直接返回取消成功(true)
// 如果任务还没有开始进行时,发起取消,是可以取消成功的。
// 如果取消时,任务已经在运行了,mayInterruptIfRunning 为 true 的话,就可以打断运行中的线程
// mayInterruptIfRunning 为 false,表示不能打断直接返回
boolean cancel(boolean mayInterruptIfRunning);
// 返回线程是否已经被取消了,true 表示已经被取消了
// 如果线程已经运行结束了,isCancelled 和 isDone 返回的都是 true
boolean isCancelled();
// 线程是否已经运行结束了
boolean isDone();
// 等待结果返回
// 如果任务被取消了,抛 CancellationException 异常
// 如果等待过程中被打断了,抛 InterruptedException 异常
V get() throws InterruptedException, ExecutionException;
// 等待,但是带有超时时间的,如果超时时间外仍然没有响应,抛 TimeoutException 异常
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
-
get 메서드의 주요 기능은 Callable 비동기 작업의 실행 결과를 가져 오는 것입니다. 매개 변수없이 가져 오기는 반환하기 전에 작업 실행이 완료 될 때까지 기다립니다. 매개 변수가있는 get 메서드는 고정 된 시간을 설정할 수 있습니다. 설정된 시간 내에 작업이 성공적으로 실행되지 않은 경우 , 예외를 직접 반환합니다. 실제 작업에서는 get parameter 메소드를 더 많이 사용하고 get parameterless 메소드를 덜 사용하여 작업 실행이 너무 느리고 대부분의 스레드가 대기하여 스레드 고갈 문제를 일으키는 것을 방지하는 것이 좋습니다.
-
취소 방법은 주로 작업을 취소하는 데 사용됩니다. 작업이 실행되지 않은 경우 취소 할 수 있습니다. 작업이 이미 실행중인 경우 취소하지 않도록 선택하거나 실행중인 작업을 직접 중단 할 수 있습니다.
그렇다면 여기에 문제가 있습니다 Callable과 Future는 모두 인터페이스입니다. Future를 통해 Callable을 제어하는 방법은 무엇입니까? 중간 클래스를 만들어 Future 인터페이스를 구현 한 다음 Callable을 결합하고 마지막으로 Future 인터페이스의 메서드를 통해 제어 할 수 있습니다. 여기의 특정 논리는 FutureTask에서 볼 수 있습니다.
3. FutureTask
Runnable과 Callable은 모두 스레드가 수행 할 작업을 나타낼 수 있습니다. 그러면이 두 인터페이스가 서로 관련되어서는 안된다는 기준으로 어떻게 서로 변환 할 수 있습니까?
- 우선, Runnable과 Callable은 extends에 의해 구현되지 않아야합니다. 직접 상속은 is-a 관계이고이 두 가지는 분명히 그렇지 않기 때문입니다.
- 그런 다음 중급 클래스 F를 도입하는 또 다른 방법이 있습니다 (다음 두 가지 조건을 충족).
- F는 Runnable을 확장합니다 : 继承 Runnable
- F {기본 호출 가능 c} : 组合 호출 가능
==> 마지막으로 위의 모든 분석을 결합하여 FutureTask의 구조를 얻습니다. Future 인터페이스 구현 및 Runnable 인터페이스 구현 및 Callable 결합
public class FutureTask<V> implements RunnableFuture<V> {
// 任务状态
private volatile int state;
private static final int NEW = 0;//线程任务创建
private static final int COMPLETING = 1;//任务执行中
private static final int NORMAL = 2;//任务执行结束
private static final int EXCEPTIONAL = 3;//任务异常
private static final int CANCELLED = 4;//任务取消成功
private static final int INTERRUPTING = 5;//任务正在被打断中
private static final int INTERRUPTED = 6;//任务被打断成功
// 组合了 Callable
private Callable<V> callable;
// 异步线程返回的结果
private Object outcome;
// 当前任务所运行的线程
private volatile Thread runner;
// 记录调用 get 方法时被等待的线程
private volatile WaitNode waiters;
//---------------------------构造方法---------------------------------
// 构造器中传入Callable接口实现对象,对callable成员变量进行初始化
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
// 任务状态初始化
this.state = NEW; // ensure visibility of callable
}
// 使用 Runnable 初始化,并传入 result 作为返回结果。
// Runnable 是没有返回值的,所以 result 一般没有用,置为 null 就好了
public FutureTask(Runnable runnable, V result) {
// Executors.callable 方法把 runnable 适配成 RunnableAdapter,
// RunnableAdapter 实现了callable,所以也就是把 runnable 直接适配成了 callable。
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
}
3.1 RunnableFuture
먼저 FutureTask에 의해 구현 된 RunnableFuture 인터페이스가 무엇인지 살펴보십시오.
- Runable 상속 : 외부를 Runnable로 전환
- Inherit Future : Future의 Callable 제어 실현
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
FutureTask가 Future 인터페이스와 Runnable 인터페이스에서 메소드를 구현하는 방법을 살펴 보겠습니다.
3.2 미래 인터페이스 방법 구현
- Future의 실현을 통해 Callable의 결합은 두 가지의 결합을 실현합니다.
- 생성자는 Callable에서 전달
- 결과 연산을 반환하는 Future 메서드 구현
- FutureTask는 Runnable을 구현하고 생성자가 Callable에 전달되면 Runnable로 직접 변환됩니다.
가져 오기
get에는 무한 차단과 타임 아웃의 두 가지 방법이 있습니다. 일반적으로 타임 아웃이있는 방법을 권장합니다. 소스 코드는 다음과 같습니다.
public V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
if (unit == null)
throw new NullPointerException();
int s = state;
// 如果任务已经在执行中了,并且等待一定的时间后,仍然在执行中,直接抛出异常
if (s <= COMPLETING &&
(s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
throw new TimeoutException();
// 任务执行成功,返回执行的结果
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 (;;) {
// 如果线程已经被打断了,删除,抛异常
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
}
// 当前任务状态
int s = state;
// 当前任务已经执行完了,返回
if (s > COMPLETING) {
// 当前任务的线程置空
if (q != null)
q.thread = null;
return s;
}
// 如果正在执行,当前线程让出 cpu,重新竞争,防止 cpu 飙高
else if (s == COMPLETING) // cannot time out yet
Thread.yield();
// 如果第一次运行,新建 waitNode,当前线程就是 waitNode 的属性
else if (q == null)
q = new WaitNode();
// 默认第一次都会执行这里,执行成功之后,queued 就为 true,就不会再执行了
// 把当前 waitNode 当做 waiters 链表的第一个
else if (!queued)
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
// 如果设置了超时时间,并过了超时时间的话,从 waiters 链表中删除当前 wait
else if (timed) {
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
removeWaiter(q);
return state;
}
// 没有过超时时间,线程进入 TIMED_WAITING 状态
LockSupport.parkNanos(this, nanos);
}
// 没有设置超时时间,进入 WAITING 状态
else
LockSupport.park(this);
}
}
취소
작업을 취소하고 실행중인 경우 중단하십시오.
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&//任务状态不是创建 并且不能把 new 状态置为取消,直接返回 false
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
// 进行取消操作,打断可能会抛出异常,选择 try finally 的结构
try {
// in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt();
} finally {
// final state
//状态设置成已打断
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
// 清理线程
finishCompletion();
}
return true;
}
3.3 Runnable 인터페이스 방법 구현
운영
run 메소드를 직접 호출하거나 호출을 위해 새 스레드를 열 수 있습니다.
- run 메소드는 반환 값이 없으며, 결과 속성 (set (result))에 값을 할당하면 get시 결과 속성에서 반환 값을 얻을 수 있습니다.
- FutureTask의 두 생성자는 최종적으로 Callable로 변환되므로 run 메소드 실행시 Callable의 call 메소드 만 실행하면됩니다 .c.call () 코드 실행시 입력 매개 변수가 Runnable이면 호출 경로 c.call ()-> RunnableAdapter.call ()-> Runnable.run ()이며 입력 매개 변수가 Callable이면 직접 호출합니다.
public void run() {
// 状态不是任务创建,或者当前任务已经有线程在执行了,直接返回
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
// 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);
}
// 给 outcome 赋值
if (ran)
set(result);
}
} finally {
runner = null;
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
3.4 호출 가능으로 실행
- 생성자는 Runnable 및 반환 값을 전달하고 변환 후 callable에 할당합니다.
public FutureTask(Runnable runnable, V result){
// 将转化的Callable赋值给callable
this.callable = Executors.callable(runnable, result);
}
- 어댑터 모드 : Executors.callable ()-> RunnableAdpter
// 转化 Runnable 成 Callable 的工具类
// 自己实现Callable接口
static final class RunnableAdapter<T> implements Callable<T> {
final Runnable task;
final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
// 重写call方法,返回result
public T call() {
task.run();
return result;
}
}
마지막으로 FutureTask가 수행하는 작업을 요약합니다.
- Future의 모든 방법을 실현하고 작업 실행 결과 획득, 작업 취소, 작업 중단 등 작업에 대한 특정 관리 기능을 갖습니다.
- Callable을 결합하고 Runnable을 구현하며 Callable과 Runnnable을 직렬로 연결합니다.
- 매개 변수가있는 작업과없는 작업의 두 가지 정의 방법이 통합되어 사용하기 편리합니다.