Executor中出现意外死锁

时间:2014-02-26 11:29:40

标签: java concurrency threadpool deadlock executorservice

我在ThreadPoolExecutor中运行任务时发现了一个意外的死锁。

这个想法是启动更改标志的辅助任务的主要任务。 主任务暂停,直到辅助任务更新标志。

  • 如果corePoolSize> = 2,则主任务按预期完成。
  • 如果corePoolSize< 2,则辅助任务似乎已被强制执行但从未启动。
  • 使用SynchronousQueue,即使corePoolSize = 0,主任务也会完成。

我想知道:

  • 造成僵局的原因是什么?这似乎并不明显 文档。
  • 为什么使用SynchronousQueue而不是LinkedBlockingQueue可以防止死锁?
  • corePoolSize = 2是一个安全值来防止这种死锁吗?

    import java.util.concurrent.*;
    class ExecutorDeadlock {
        /*------ FIELDS -------------*/
        boolean halted = true;
        ExecutorService executor;
        Runnable secondaryTask = new Runnable() {
            public void run() {
                System.out.println("secondaryTask started");
                halted = false;
                System.out.println("secondaryTask completed");
                }
        };
        Runnable primaryTask = new Runnable() {
            public void run() {
            System.out.println("primaryTask started");
            executor.execute(secondaryTask);
            while (halted) {
                try {
                    Thread.sleep(500);
                }
                catch (Throwable e) {
                    e.printStackTrace();
                }
            }
            System.out.println("primaryTask completed");
          }
       };
    
       /*-------- EXECUTE -----------*/
       void execute(){
            executor.execute(primaryTask);
       }
    
       /*-------- CTOR -----------*/
       ExecutorDeadlock(int corePoolSize,BlockingQueue<Runnable> workQueue) {
            this.executor = new ThreadPoolExecutor(corePoolSize, 4,0L, TimeUnit.MILLISECONDS, workQueue);
       }
    
       /*-------- TEST -----------*/
       public static void main(String[] args) {
            new ExecutorDeadlock(2,new LinkedBlockingQueue<>()).execute();
            //new ExecutorDeadlock(1,new LinkedBlockingQueue<>()).execute();
           //new ExecutorDeadlock(0,new SynchronousQueue<>()).execute();
       }
    }
    

1 个答案:

答案 0 :(得分:6)

你如何期望这对线程数&lt; 2 if

起作用
  • 您只有1个执行程序线程
  • 首先尝试将辅助任务添加到执行程序队列,然后为其启动WAITS

当池中有空闲执行程序时,执行程序服务从队列中获取任务。在你的情况下(&lt; 2)执行程序线程永远不会被第一个任务释放。 这里没有死锁问题。

修改

好的,我挖出了一些信息,这就是我发现的。首先来自ThreadPoolExecutor

的一些信息
  

任何BlockingQueue都可用于转移和保留提交的任务。   此队列的使用与池大小调整相互作用:

If fewer than corePoolSize threads are running, the Executor always prefers adding a new thread rather than queuing.
If corePoolSize or more threads are running, the Executor always prefers queuing a request rather than adding a new thread.
If a request cannot be queued, a new thread is created unless this would exceed maximumPoolSize, in which case, the task will be rejected.

好的,现在和queuess offer方法一样

SyncQueue:

  

如果另一个线程是,则将指定的元素插入此队列   等着收到它。

的LinkedBlockingQueue

  

将指定的元素插入此队列,等待空间变为可用。

offer方法的返回值确定新任务将在新线程中排队或运行。

由于LinkedBlockingQueue将新任务排队,因为它可以存在容量,因此任务被排队并且不会产生新线程。但是SyncQueu不会排队另一个任务,因为没有其他线程在等待某些事情被排队(offer在任务未入队时返回false)这就是为什么会产生新的执行程序线程。

如果您阅读ThreadPoolExecutor LinkedBlockingQueueSynchronousQueue的javadoc并检查execute方法的实施情况,您将得出相同的结论。

所以你错了,文档中有explenation:)