ThreadPoolExecutor中的submit()方法详细讲解
来源:互联网 发布:鱼缸水景设计软件 编辑:程序博客网 时间:2024/06/06 02:40
ThreadPoolExecutor中的submit()方法详细讲解
在使用线程池的时候,发现除了execute()
方法可以执行任务外,还发现有一个方法submit()
可以执行任务。
submit()
有3个参数不一的方法,这些方法都是在ExecutorService
接口中声明的,在AbstractExecutorService
中实现,而ThreadPoolExecutor
继承AbstractExecutorService
。
<T> Future<T> submit(Callable<T> callable);<T> Future<T> submit(Runnable var1, T result);Future<?> submit(Runnable runnable);
我们可以看到submit()
的参数既可以是Runnable
,又可以是Callable
。对于Runnable
我们是比较熟的,它是线程Thread
所执行的任务,里面有一个run()
方法,是任务的具体执行操作。那么Callable
呢?我们一起看下他们的代码吧。
public interface Runnable { void run();}public interface Callable<V> { V call() throws Exception;}
Runnable
这里就不介绍了,Callable
接口定义了一个call()
方法,返回一个Callable
指定的泛型类,并且call()
调用的时候会抛出异常。通过比较Runnable
和Callable
还看不什么端倪,那么我们就看看内部实现吧。
submmit()
参数解析
这里重点分析submit()
带参数Runnable
和Callable
的方法
public Future<?> submit(Runnable task) { if (task == null) throw new NullPointerException(); RunnableFuture<Void> ftask = newTaskFor(task, null); execute(ftask); return ftask;}public <T> Future<T> submit(Callable<T> task) { if (task == null) throw new NullPointerException(); RunnableFuture<T> ftask = newTaskFor(task); execute(ftask); return ftask;}
我们发现2者的实现没有任何的差异,唯一就是submit()
参数不同。
参数传入newTaskFor()
方法,那么可以肯定就是在这个方法里做了什么操作。
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { return new FutureTask<T>(runnable, value);}protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { return new FutureTask<T>(callable);}
newTaskFor()
的目的就是创建一个FutureTask
对象,那我们追踪到FutureTask
的构造方法(FutureTask
非常关键,后面会分析)。
public FutureTask(Runnable runnable, V result) { this.callable = Executors.callable(runnable, result); this.state = NEW; }public FutureTask(Callable<V> callable) { if (callable == null)throw new NullPointerException(); this.callable = callable; this.state = NEW; }
到了这里我们知道,其实Runnable
会在这里转化成Callable
。我们来看下Executors.callable()
具体实现。
public static <T> Callable<T> callable(Runnable task, T result) { if (task == null) throw new NullPointerException(); return new RunnableAdapter<T>(task, result);}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; }}
Executors.callable()
创建了一个RunnableAdapter
对象,RunnableAdapter
实现了Callable
接口,在call()
方法中调用了传入的Runnable
的run()
,并且将传入的result
参数返回。
也就是说我们调用submit()
传入的Runnbale
最终会转化成Callable
,并且返回一个result
值(如果我们传入这个参数则返回这个参数,不传入则返回null)。
到这里我们讲清楚了submit()
的参数的区别和内部实现,submit()
方法有一个返回值Future
,下面我们来分析一下返回值Future
。
submit()
的返回值Future
上面分析submit()
源码可知,submit()
返回的是一个RunnableFuture
类对象,真正是通过newTaskFor()
方法返回一个new FutureTask()
对象。所以submit()
返回的真正的对象是FutureTask
对象。
那么FutureTask
是什么,我们来看下它的类继承关系。
public class FutureTask<V> implements RunnableFuture<V> { ...}public interface RunnableFuture<V> extends Runnable, Future<V> { void run();}
通过继承关系我们可以明确的知道其实FutureTask
就是一个Runnable
。并且有自己run()
实现。我们来看下FutureTask
的run()
是如何实现的。
public void run() { if (state != NEW || !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread())) return; 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); } } finally { // runner must be non-null until state is settled to // prevent concurrent calls to run() runner = null; // state must be re-read after nulling runner to prevent // leaked interrupts int s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); } }
我们在new FutureTask()
对象的时候,在FutureTask
构造方法中会对state
状态赋值为NEW
,并且传入一个callable
对象。通过FutureTask
的run()
我们可以知道,其实就通过state
状态判断,调用callable的call()
。(如果传入的参数是Runnable
,Runnable
在RunnableAdapter
类中转化时,在call()
中,其实调用的就是Runnable
的run()
方法)。
所以在submit()
方法中,调用了一个execute(task)
的方法,实际执行的是FutureTask
的run()
,而FutureTask
的run()
调用的是Callable
的call()
方法。
说了这么多,submit()
最后执行的还是传入的Runnable
的run()
或Callable
的call()
方法。好像没有FutureTask
什么事啊。
其实不是,submit()
返回FutureTask
对象,通过这个FutureTask
对象调用get()
可以返回submit()
方法传入的一个泛型类参数result
对象,如果是Callable
直接通过call()
返回。这个返回值的可以用来校验任务执行是否成功。
- FutureTask的get()的实现
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);}
最后是通过outcome
参数将根据任务的状态将结果返回。那么outcome
参数在哪里赋值了?outcome
参数赋值的地方有好2处,一是FutureTask
的set()
,二是FutureTask
的setException()
。
set()
是在FutureTask
的run()
执行完成后,将传入的result
参数赋值给传入给set()
,赋值给outcome
参数。如果run()
报异常了会将Throwable
对象通过setException()
方法传入,赋值给outcome
变量
大家可以返回上面的run()
查看下。
protected void set(V v) { if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) { outcome = v; U.putOrderedInt(this, STATE, NORMAL); // final state finishCompletion(); }}protected void setException(Throwable t) { if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) { outcome = t; U.putOrderedInt(this, STATE, EXCEPTIONAL); // final state finishCompletion(); }}
submit()
使用案例
public class Test { private static final String SUCCESS = "success"; public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(3); System.out.println("------------------任务开始执行---------------------"); Future<String> future = executorService.submit(new Callable<String>() { @Override public String call() throws Exception { Thread.sleep(5000); System.out.println("submit方法执行任务完成" + " thread name: " + Thread.currentThread().getName()); return SUCCESS; } }); try { String s = future.get(); if (SUCCESS.equals(s)) { String name = Thread.currentThread().getName(); System.out.println("经过返回值比较,submit方法执行任务成功 thread name: " + name); } } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("-------------------main thread end---------------------"); }}
打印结果:
------------------任务开始执行---------------------call()调用开始: 1496899867882submit方法执行任务完成: 1496899872897 thread name: pool-1-thread-1经过返回值比较,submit方法执行任务成功 thread name: main-------------------main thread end---------------------
主线程会一直阻塞,等待线程池中的任务执行完后,在执行后面的语句。
- ThreadPoolExecutor中的submit()方法详细讲解
- ThreadPoolExecutor类execute 与submit方法的区别
- 让ThreadPoolExecutor的workQueue占满时自动阻塞submit()方法
- ThreadPoolExecutor讲解
- Android中的Intent详细讲解
- Android中的Intent详细讲解
- Android中的Intent详细讲解
- Android中的Intent详细讲解
- Android中的Intent详细讲解
- Android中的Intent详细讲解
- Android中的Intent详细讲解
- Android中的Intent详细讲解
- Android中的Intent详细讲解
- Android中的Intent详细讲解
- Android中的Intent详细讲解
- Android中的JSON详细讲解
- Android中的Intent详细讲解
- android中的json详细讲解
- java封装的几个线程池介绍
- gc和内存分配
- 慕课网简易扑克牌游戏
- 获取layer.open弹出层的返回值
- tomcat jvm优化
- ThreadPoolExecutor中的submit()方法详细讲解
- 创建maven项目的另一种方式
- 深度学习与计算机视觉系列(3)_线性SVM与SoftMax分类器
- MYSQL主从复制
- windows下ffmpeg使用dshow
- 一个文件实现安卓滚轮选择控件
- 投影坐标系与地理坐标系之间的关系
- HTML常用标签使用
- java中Atomic类之AtomicLongArray