2011-02-10 68 views
9

我有一个要求任务异步执行,同时放弃任何进一步的请求,直到任务完成。单线程的任务,而不排队进一步的请求

同步该方法只是排队的任务,不跳过。我最初认为要使用SingleThreadExecutor,但它也排队完成任务。然后,我查看了ThreadPoolExecutor,但它读取队列以获取要执行的任务,因此将执行一个任务,并且排队最少一个任务(其他人可以使用ThreadPoolExecutor.DiscardPolicy放弃)。

我唯一能想到的就是使用Semaphore来阻塞队列。我用下面的例子来展示我想要达到的目标。有一种更简单的方法吗?我错过了明显的东西吗?

import java.util.concurrent.*; 

public class ThreadPoolTester { 
    private static ExecutorService executor = Executors.newSingleThreadExecutor(); 
    private static Semaphore processEntry = new Semaphore(1); 

    public static void main(String[] args) throws InterruptedException { 
     for (int i = 0; i < 20; i++) { 
      kickOffEntry(i); 

      Thread.sleep(200); 
     } 

     executor.shutdown(); 
    } 

    private static void kickOffEntry(final int index) { 
     if (!processEntry.tryAcquire()) return; 
     executor. 
      submit(
       new Callable<Void>() { 
        public Void call() throws InterruptedException { 
         try { 
          System.out.println("start " + index); 
          Thread.sleep(1000); // pretend to do work 
          System.out.println("stop " + index); 
          return null; 

         } finally { 
          processEntry.release(); 
         } 
        } 
       } 
      ); 
    } 
} 

样本输出

start 0 
stop 0 
start 5 
stop 5 
start 10 
stop 10 
start 15 
stop 15 

以axtavt答案,并转换上述例子给出了以下简单的解决方案。

import java.util.concurrent.*; 

public class SyncQueueTester { 
    private static ExecutorService executor = new ThreadPoolExecutor(1, 1, 
      1000, TimeUnit.SECONDS, 
      new SynchronousQueue<Runnable>(), 
      new ThreadPoolExecutor.DiscardPolicy()); 

    public static void main(String[] args) throws InterruptedException { 
     for (int i = 0; i < 20; i++) { 
      kickOffEntry(i); 

      Thread.sleep(200); 
     } 

     executor.shutdown(); 
    } 

    private static void kickOffEntry(final int index) { 
     executor. 
      submit(
       new Callable<Void>() { 
        public Void call() throws InterruptedException { 
         System.out.println("start " + index); 
         Thread.sleep(1000); // pretend to do work 
         System.out.println("stop " + index); 
         return null; 
        } 
       } 
      ); 
    } 
} 

回答

10

它看起来像由SynchronousQueue与预期的政策支持执行你想要做什么:

executor = new ThreadPoolExecutor(
    1, 1, 
    1000, TimeUnit.SECONDS, 
    new SynchronousQueue<Runnable>(), 
    new ThreadPoolExecutor.DiscardPolicy()); 
+0

Coudl你告诉我,为什么你喜欢使用一个传播信号参考其他线程的堆栈DiscardPolicy捕获RejectedExecutionException? – 2012-10-16 01:06:11

0

如果没有排队,没有必要为遗嘱执行人我说。单独使用信号量似乎就够了。我使用下面的代码来避免在运行时运行相同的代码。只需确保semaphorestatic volatile,这使得信号的唯一信号量的类,并尽快将其改变

if (this.getSemaphore().tryAcquire()) { 
     try { 
      process(); 
     } catch (Exception e) { 
     } finally { 
      this.getSemaphore().release(); 
     } 
} 
else { 
    logger.info(">>>>> Job already running, skipping go"); 
} 
+0

该任务需要在单独的线程中运行,以便主线程不被阻塞或受到其他影响(“主线”实际上是一个swing应用程序) – 2011-02-10 08:57:21