Java并发编程 一文看懂Callable和Runnable使用及原理
背景
安卓开发中很多时候,我们都是选择使用已有框架做异步任务,有些时候,线程一旦启动,不容易终止,此文解析下Runnable和Callable的使用,补充下基础知识。
一、Callable和Runnable
二者都是线程创建时执行耗时操作的位置,二者都只是一个接口,区别是Callable有返回值。
public interface Runnable {
public abstract void run();
}
public interface Callable<V> {
// call方法会返回V类型的结果
V call() throws Exception;
}
二、Runnable在线程中的使用
Runnable需要依赖Thread或者ExecutorService使用,有三种使用方式
// 1、重写Thread的run方法
new Thread() {
@Override
public void run() {
}
}.start();
// 2、创建Runnable对象作为参数
new Thread(new Runnable() {
@Override
public void run() {
}
}).start();
// 3、借助于ExecutorService,使用submit或者execute,一般结合FutureTask使用
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.submit(new Runnable() {
@Override
public void run() {
}
});
executorService.execute(new Runnable() {
@Override
public void run() {
}
});
本质上重写Thread的run方法本质也是Runnable对象
// Thread实现了Runnable接口
public class Thread implements Runnable {
private Runnable target;
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
this.target = target;
}
@Override
public void run() {
if (target != null) {
target.run();
}
}
}
三、Callable在线程中的使用
Callable利用ExecutorService的submit方法去启动call方法
ExecutorService executorService = Executors.newFixedThreadPool(10);
// submit方法,会等待结果返回
Callable<String> stringCallable = new Callable<String>() {
@Override
public String call() throws Exception {
}
};
Future<String> result = executorService.submit(stringCallable);
四、Callable&Runnable使用相关类原理解析
我们发现,Callable和Runnable的使用借用了Executor、ExecutorService、Executors、Future、FutureTask。并且这几个类都是很不错的实现,我们解析下这几个类的功能和原理。
1、Executor用于执行已提交Runnable任务的对象,接口类
public interface Executor {
void execute(Runnable command);
}
2、Future用于获取异步任务的结果,接口类
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;
}
3、ExecutorService是对Executor接口的扩展,提供一些接口去操作任务集合,同时支持Callable,返回Future用于操作任务结果
public interface ExecutorService extends Executor {
void shutdown();
List<Runnable> shutdownNow();
boolean isShutdown();
// 如果所有任务都执行完了shutdown,返回true
boolean isTerminated();
// 阻塞直到所有任务执行完成或被shutdown或被中断
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;
// 执行一个任务集合,同时设置执行超时时间
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException;
// 执行一个任务集合,执行完一个任务就返回一个结果。无论主动结束任务还是异常,剩余的任务也不会执行
<T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException;
<T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
4、FutureTask继承Runnable,可以兼容Thread使用Runnable;实例化接收Runnable和Callable,任何任务都可被包装执行;实现了Future接口,可以取消任务,设置超时任务。
// 一个可被管理的Runnable
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
public class FutureTask<V> implements RunnableFuture<V> {
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
public FutureTask(Runnable runnable, V result) {
// Executors的包装接口,用Callable包装了Runnable
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
public boolean isCancelled() { return state >= CANCELLED;}
public boolean isDone() {return state != NEW;}
public boolean cancel(boolean mayInterruptIfRunning) {
// 1、mayInterruptIfRunning为true,执行中也会被中断
// 2、mayInterruptIfRunning为false,没执行的才会被取消
}
// 获取执行结果,这里可能被阻塞
public V get() throws InterruptedException, ExecutionException {}
// 规定时间内获取执行结果
public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {}
// 任务执行完成、被cancel、出现异常,会调用这个方法,可以重写此方法作为监听
protected void done() { }
// 任务执行完,调用此方法返回结果
protected void set(V v) {}
// 执行出现异常,调用此方法释放资源,设置任务状态
protected void setException(Throwable t) {}
// 这里会执行实例化传入的任务
public void run() {}
5、Executors提供了一些工具方法,用来提供线程池,和包装类
// AbstractExecutorService实现了ExecutorService的submit、invokeAny、invokeAll接口
public abstract class AbstractExecutorService implements ExecutorService {
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
// 提交任务后返回的是FutureTask,说明可以利用FutureTask接口操作任务
return new FutureTask<T>(runnable, value);
}
public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return doInvokeAny(tasks, true, unit.toNanos(timeout));
}
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException {
}
}
// 这个类包装了线程池,用来执行任务.同时实现了ExecutorService的shutdown、isShutdown、isTerminated、awaitTermination接口
public class ThreadPoolExecutor extends AbstractExecutorService {
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN);
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
// 其他实现就不列出了,有兴趣的可以自行了解源码
}
// 提供了一些方法用来创建ThreadPoolExecutor,包装Runnable
public class Executors {
// 这里创建ThreadPoolExecutor,返回包装了可以操作任务的线程池
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
}
// 返回了一个单线程的线程池
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
}
private static final class RunnableAdapter<T> implements Callable<T> {
private final Runnable task;
private final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
public T call() {
task.run();
return result;
}
}
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
// 这里其实是把Runnable包装成了Callable,同时绑定了返回值
return new RunnableAdapter<T>(task, result);
}
}
注:Executors可以创建很多类型的线程池,这里就不做具体分析,有需求可以阅读此类,选择合适的线程池操作。
五、一些不错的代码
1、实现一个封装好的有序执行的队列,在AsyncTask有使用。
class SerialExecutor implements Executor {
final Queue<Runnable> tasks = new ArrayDeque<>();
final Executor executor;
Runnable active;
SerialExecutor(Executor executor) {
this.executor = executor;
}
public synchronized void execute(final Runnable r) {
tasks.add(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (active == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((active = tasks.poll()) != null) {
executor.execute(active);
}
}
}}
2、实现socket连接下request请求
class NetworkService implements Runnable {
private final ServerSocket serverSocket;
private final ExecutorService pool;
public NetworkService(int port, int poolSize)
throws IOException {
serverSocket = new ServerSocket(port);
pool = Executors.newFixedThreadPool(poolSize);
}
public void run() { // run the service
try {
for (;;) {
pool.execute(new Handler(serverSocket.accept()));
}
} catch (IOException ex) {
pool.shutdown();
}
}
}
class Handler implements Runnable {
private final Socket socket;
Handler(Socket socket) { this.socket = socket; }
public void run() {
// read and service request on socket
}
}
总结
1、Callable的出现,使得任务可以有返回值。
2、Future的get和cancel等接口,使得线程可以被取消,可以随时get获取结果。
3、Executor接口用来执行Runnable
4、ExecutorService扩展了Executor,提供了shutdown接口,同时支持执行Runnable和Callable,和任务集合。返回Future,可以通过Future操作任务。这里我们可以发现,操作线程任务有两种方式,一种通过ExecutorService的shutdown,另一种通过Future的cancel方法。
5、Executors提供ThreadPoolExecutor等线程池包装类,用来执行异步任务,ThreadPoolExecutor同时实现了ExecutorService的接口,可以操作任务。
6、Future、FutureTask、Executor、ExecutorService、Executors的出现兼容了Runnable接口,同时支持了Runnable返回结果。并且提供了一些不错的包装类。