Однопоточное выполнение задачи без очереди дальнейшие запросы

У меня есть требование, чтобы задача выполнялась асинхронно, отбрасывая любые дальнейшие запросы, пока задача не будет завершена.

Синхронизация метода просто ставит задачи в очередь и не пропускает их. Сначала я думал использовать SingleThreadExecutor, но он тоже ставит задачи в очередь. Затем я посмотрел на ThreadPoolExecutor, но он читает очередь, чтобы выполнить задачу, и, следовательно, будет выполнять одну задачу и как минимум одну задачу в очереди (остальные можно отбросить с помощью ThreadPoolExecutor.DiscardPolicy).

Единственное, что я могу придумать, - это использовать семафор для блокировки очереди. Я привел следующий пример, чтобы показать, чего я пытаюсь достичь. Есть способ попроще? Я пропустил что-то очевидное?

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;
                    }
                }
            );
    }
}
9
задан Michael Rutherfurd 10 February 2011 в 09:05
поделиться