线程池java submit,详解线程池execute和submit用法

在使用线程池时,我们都知道线程池有两种提交任务的方式,那么他们有什么区别呢?

1.execute提交的是Runnable类型的任务,而submit提交的是Callable或者Runnable类型的任务

2.execute的提交没有返回值,而submit的提交会返回一个Future类型的对象

3.execute提交的时候,如果有异常,就会直接抛出异常,而submit在遇到异常的时候,通常不会立马抛出异常,而是会将异常暂时存储起来,等待你调用Future.get()方法的时候,才会抛出异常

了解了以上区别以后,我们再想想,他们之间会不会有联系呢?答案是肯定的,其实在submit里面的,任务提交的时候,底层都是使用execute来提交的,我们先来看看源码

1 public Future submit(Callabletask) {2 if (task == null) throw newNullPointerException();3 RunnableFuture ftask =newTaskFor(task);4 execute(ftask);5 returnftask;6 }

上面的代码中,将 task 传进一个newTaskFor方法以后,返回一个RunnableFuture对象,然后就直接将这个对象传入execute方法里面了,所以跟据上面的代码,可以总结出三点:

1.RunnalbeFuture 是一个实现了Runnable接口的类

2.newTaskFor方法能将Callable任务转换成Runnable任务

3.通过返回类型可以判断,RunnableFuture也实现了Future接口,并且由于在方法外,可以通过Future获得值这一点看,RunnableFuture可以保存值

现在我们来看看具体是怎么实现的

首先看看FutureRunnable的run方法,因为他是runnable任务,被execute提交后肯定会运行这个任务的run方法

1 public voidrun() {2 if (state != NEW ||

3 !UNSAFE.compareAndSwapObject(this, runnerOffset,4 null, Thread.currentThread()))5 return;6 try{7 Callable c = callable;8 if (c != null && state ==NEW) {9 V result;10 booleanran;11 try{12 result = c.call();13 ran = true;14 } catch(Throwable ex) { //捕获所有异常15 result = null;16 ran = false;17 setException(ex); //有异常就保存异常18 }19 if(ran)20 set(result); //没有异常就设置返回值21 }22 } finally{23 //runner must be non-null until state is settled to24 //prevent concurrent calls to run()

25 runner = null;26 //state must be re-read after nulling runner to prevent27 //leaked interrupts

28 int s =state;29 if (s >=INTERRUPTING)30 handlePossibleCancellationInterrupt(s);31 }32 }

可以看到,runnable 的 run 方法里,直接调用了他封装的 callable 任务的 call()方法 ,如果有异常,就直接将异常放入 这个类的静态变量里 ,如果没有异常,就将返回值放入自己的局部变量里,我们来看看上面代码中的Set(result)方法吧

1 protected voidset(V v) {2 if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {3 outcome = v;4 UNSAFE.putOrderedInt(this, stateOffset, NORMAL); //final state

5 finishCompletion();6 }7 }

可以看到标红的部分,其实就是将传进来的值,保存到一个叫做 outcome 的静态变量里面了,而相对应的,由于一开始提交任务时返回了本类的引用(Future对象),所以可以通过引用访问静态变量的方式,访问到返回值了,Future.get() 在RunnableFuture中的实现如下

1 public V get() throwsInterruptedException, ExecutionException {2 int s =state;3 if (s <=COMPLETING) //如果线程还没运行完成4 s = awaitDone(false, 0L); //阻塞等待5 returnreport(s); //返回值或者异常6 }

上面代码中的report(s)实现如下:

private V report(int s) throwsExecutionException {

Object x=outcome;if (s ==NORMAL)return(V)x;if (s >=CANCELLED)throw newCancellationException();throw newExecutionException((Throwable)x);

}

现在我们再总结一下吧:首先callable没有什么神奇之处,通过submit提交之后,会被包装成RunnableFuture,同时被当作返回值传回,在RunnableFuture的run方法中,会调用它保存的callable任务的call方法,同时跟据是否有异常,来决定保存返回值或者异常到其静态变量中,最后外部通过get方法就可以访问到返回值啦!

小技巧:在使用future.get() 获取返回值的时候,如果当前这个值还没有计算出来,那么就会产生阻塞,直到获取到值,这个时候我们可以用 future.isDone 检查任务的状态,再根据状态去get这个值,这样就不会阻塞了

请尊重作者的辛苦付出,如果转载请注明出处,谢谢

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值