美文网首页
ThreadPoolExecutor afterExecute无

ThreadPoolExecutor afterExecute无

作者: kjstart | 来源:发表于2020-12-17 03:52 被阅读0次

    先说结论, 如果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);
        }
    }
    

    这样写有没有问题?

    反正ActiveMQ也是这样用的
    https://github.com/apache/activemq/blob/290a93d91f09ff86d0f977324dc91f4d3f26e8a8/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/KahaDBStore.java#L1741

    https://github.com/apache/activemq/blob/290a93d91f09ff86d0f977324dc91f4d3f26e8a8/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/KahaDBStore.java#L339

    相关文章

      网友评论

          本文标题:ThreadPoolExecutor afterExecute无

          本文链接:https://www.haomeiwen.com/subject/kxsagktx.html