线程池相关我爱编程

ThreadPoolExecutor使用错误导致死锁

2015-01-26  本文已影响7973人  AGIHunt

背景

服务器现象及故障恢复步骤

疑问

定位分析

且其构造函数相关含义为:

ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)
Creates a new ThreadPoolExecutor with the given initial parameters.
Parameters:
corePoolSize - the number of threads to keep in the pool, even if they are idle.
maximumPoolSize - the maximum number of threads to allow in the pool.
keepAliveTime - when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.
unit - the time unit for the keepAliveTime argument.
workQueue - the queue to use for holding tasks before they are executed. This queue will hold only the Runnable tasks submitted by the execute method.
threadFactory - the factory to use when the executor creates a new thread.
handler - the handler to use when execution is blocked because the thread bounds and queue capacities are reached.
Throws:
IllegalArgumentException - if corePoolSize or keepAliveTime less than zero, or if maximumPoolSize less than or equal to zero, or if corePoolSize greater than maximumPoolSize.
NullPointerException - if workQueue or threadFactory or handler are null.
    ...
       protected static final ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 100, 2, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>(),
                new ThreadFactory() {
                    private AtomicInteger id = new AtomicInteger(0);

                    @Override
                    public Thread newThread(Runnable r) {
                        Thread thread = new Thread(r);
                        thread.setName("home-service-" + id.addAndGet(1));
                        return thread;
                    }
                }, new ThreadPoolExecutor.CallerRunsPolicy());

       public static void main(String[] args) throws InterruptedException, ExecutionException {
            Future<Long> f1 = executor.submit(new Callable<Long>() {
                @Override
                public Long call() throws Exception {
                    Thread.sleep(1000); //延时以使得第二层的f3在第一层的f2占用corePoolSize后才submit
                    Future<Long> f3 = executor.submit(new Callable<Long>() {
                        @Override
                        public Long call() throws Exception {

                            return -1L;
                        }
                    });
                    System.out.println("f1.f3" + f3.get());
                    return -1L;
                }
            });
            Future<Long> f2 = executor.submit(new Callable<Long>() {
                @Override
                public Long call() throws Exception {
                    Thread.sleep(1000);//延时
                    Future<Long> f4 = executor.submit(new Callable<Long>() {
                        @Override
                        public Long call() throws Exception {

                            return -1L;
                        }
                    });
                    System.out.println("f2.f4" + f4.get());
                    return -1L;
                }
            });
            System.out.println("here");
            System.out.println("f1" + f1.get());
            System.out.println("f2" + f2.get());
        }
    ...

运行程序后发现只打出一行日志"here", 并且进程没有结束,取其jstack:

    ...
    "home-service-2" prio=5 tid=7fe2aa15b800 nid=0x10dcef000 waiting on condition [10dcee000]
       java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <7f371ac80> (a java.util.concurrent.FutureTask$Sync)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:811)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:969)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1281)
        at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:218)
        at java.util.concurrent.FutureTask.get(FutureTask.java:83)
        at com.xxxxxx.productfront.service.HomeService$3.call(HomeService.java:136)
        at com.xxxxxx.productfront.service.HomeService$3.call(HomeService.java:1)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
        at java.util.concurrent.FutureTask.run(FutureTask.java:138)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
        at java.lang.Thread.run(Thread.java:695)

    "home-service-1" prio=5 tid=7fe2aa0b8800 nid=0x10dbec000 waiting on condition [10dbeb000]
       java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <7f36c5800> (a java.util.concurrent.FutureTask$Sync)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:811)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:969)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1281)
        at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:218)
        at java.util.concurrent.FutureTask.get(FutureTask.java:83)
        at com.xxxxxx.productfront.service.HomeService$2.call(HomeService.java:121)
        at com.xxxxxx.productfront.service.HomeService$2.call(HomeService.java:1)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
        at java.util.concurrent.FutureTask.run(FutureTask.java:138)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
        at java.lang.Thread.run(Thread.java:695)
    ...
    "main" prio=5 tid=7fe2ab000800 nid=0x1051c9000 waiting on condition [1051c8000]
       java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <7f369cab0> (a java.util.concurrent.FutureTask$Sync)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:811)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:969)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1281)
        at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:218)
        at java.util.concurrent.FutureTask.get(FutureTask.java:83)
        at com.xxxxxx.productfront.service.HomeService.main(HomeService.java:141)
    ...

可见确实会造成'''死锁''',而如果去掉f1和f2内的sleep延时,而把延时放到f2之前,则f1, f2, f3, f4均能成功完成。

结论

如何处理

参考资料

上一篇 下一篇

猜你喜欢

热点阅读