先说结论, 如果afterExecute方法里拿不到你提交的Runnable, 试试用execute提交任务.
简介
为了方便码农监控线程池里庄稼的长势, ThreadPoolExecutor给我们提供了两个钩子方法.
void beforeExecute(Thread t, Runnable r)
在Runnable被线程池运行之前调用, 可见这时已分配线程. 如果这个方法里抛出异常, 不会触发afterExecute.
void afterExecute(Runnable r, Throwable t)
在Runnable被线程池运行之后调用, 如果没有异常t=null.
具体可以看源代码的注释, 另外重写时记得先调用原super方法, 例如super.afterExecute(r, t);
我遇到的坑
我们在提交的Runnable上等待了对象, 希望通过线程执行时手工释放锁来提交下一个Runnable, 使线程池持续运行. 实际情况是有时Runnable莫名其妙的死了, 然后就没有然后了.
所以我希望在afterExecute里notify一下wait在上面的提交代码. 但刚开始用submit提交的Runnable, afterExecute里拿到的Runnable基本是空的. 后来发现submit时由于要处理Future, 线程池会在我们的Runnable外面再包一层对象, 而且最后把我们的对象搞丢了.
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
所以, 解决办法就是如果想用afterExecute搞事情, 就用execute方法提交Runnable.
实例
简单介绍一下情况就上代码了, 测试代码输出是这样的, 看懂了就不用往下看了.
=====submit task 1=====
pool-1-thread-1 beforeExeccute got runnable: FutureTask
Running task, id: 1
afterExecute got runnable: FutureTask
=====execute task 2=====
pool-1-thread-1 beforeExeccute got runnable: TestTask
Running task, id: 2
afterExecute got runnable: TestTask
Got task id: 2
测试代码
public class ThreadPoolAfterExecuteTest {
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor workerPool = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(10)) {
@Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
out(t.getName()+" beforeExeccute got runnable: " + r.getClass().getSimpleName());
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
out("afterExecute got runnable: " + r.getClass().getSimpleName());
if (r instanceof TestTask) {
System.out.println("Got task id: " + ((TestTask) r).id);
}
synchronized (r) {
r.notifyAll();
}
}
};
out("=====submit task 1=====");
workerPool.submit(new TestTask(1));
TimeUnit.SECONDS.sleep(1);
out("=====execute task 2=====");
workerPool.execute(new TestTask(2));
}
static class TestTask implements Runnable {
private long id;
public TestTask(long id) {
this.id = id;
}
@Override
public void run() {
out("Running task, id: " + id);
}
}
static void out(String text) {
System.out.println(text);
}
}
网友评论