выполнить несколько Runnables из одного потока после указанного времени ожидания - PullRequest
0 голосов
/ 07 февраля 2012

Я хочу запланировать Runnables и выполнять их один за другим из того же потока, но не раньше, чем после указанного времени ожидания. Есть ли стандартный способ сделать это?

вот мой код:

public class DelayedExecutor {
    private final long           _timeout;
    private final List<Runnable> _tasks = new LinkedList<>();
    private final ThreadFactory  _factory;
    private final Thread         _supervisor;

    public DelayedExecutor(long timeout, ThreadFactory factory) {
        _timeout = timeout;
        _factory = factory;

        _supervisor = new Thread(new Runnable() {
            @Override
            public void run() {
                while (_supervisor.isInterrupted()) {
                    try {
                        Thread.sleep(_timeout);
                    }
                    catch (InterruptedException e) {
                        if (_supervisor.isInterrupted())
                            break;
                    }

                    synchronized (_tasks) {
                        ArrayList<Runnable> prepared = new ArrayList<>(_tasks);
                        Collections.reverse(prepared);

                        execute(prepared);

                        _tasks.clear();
                    }
                }
            }
        });

        _supervisor.setDaemon(true);
        _supervisor.start();
    }

    public void schedule(Runnable runnable) {
        synchronized (_tasks) {
            _tasks.add(runnable);
        }
    }

    private void execute(final List<Runnable> tasks) {
        _factory.newThread(new Runnable() {
            @Override
            public void run() {
                for (Runnable runnable : tasks)
                    runnable.run();
            }
        });
    }
}

Ответы [ 4 ]

2 голосов
/ 07 февраля 2012

После некоторых острых комментариев я думаю, что начинаю понимать, что вы делаете, и похоже на шаблон Producer / Consumer с небольшой модификацией. Исходя из нашего чата, теперь я понимаю, что вы хотите запустить потребителя по фиксированной ставке! Это должно дать вам представление (но использовать параллельную коллекцию в вашей реализации):

public FixedRateConsumer implements Runnable
{
    private final object _lock = new object();
    // *** use a concurrent collection here ***
    private Queue<Runnable> _workQueue; 

    public FixedRateConsumer()
    {
        _workQueue = new Queue<Runnable>();
    }

    public scheduleTask(Runnable task)
    {
        synchronized(_lock)
        {
            _workQueue.put(task); 
        }
    }

    public void run()
    {
        synchronized(_lock)
        {
            while(_workQueue.poll()!=null)
            {
                _workQueue.take().run();
            }
        }
    }
}

А теперь вам просто нужно запланировать запуск потребителя с фиксированной скоростью:

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
FixedRateConsumer consumer = new FixedRateConsumer();

scheduler.scheduleAtFixedRate(consumer, /*specify initial delay*/, /*specify rate*/, /*specify TimeUnit*/);

Ваш производитель может запланировать задачу следующим образом:

// Then you just schedule your tasks like this
consumer.scheduleTask(new Runnable());
1 голос
/ 07 февраля 2012

Лучше всего использовать ScheduledThreadExecutor .Вы можете создать его с пулом из одного потока:

ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1);

Затем посмотрите методы schedule и scheduleAtFixedRate.

0 голосов
/ 07 февраля 2012

Если вы хотите запустить их все сразу, а не по порядку, тогда CountDownLatch может помочь.

int threads = 10;
final CountDownLatch ready = new CountDownLatch(threads);
final CountDownLatch start = new CountDownLatch(1);
ExecutorService executorService = Executors.newFixedThreadPool(threads);
for(int i=1; i<=threads; i++) {
   executorService.execute(new Runnable() {
    public void run() {
     ready.countDown();  //Signal that this runnable is ready
     try {
       start.await();  //Wait for the signal
     } catch(InterupptedException e) {}
     Target target = new Target();
     target.doSomeStuff();
    }
   });
}
try {
 ready.await(); //Wait till all are ready
} catch (InterruptedException e) {
           e.printStackTrace();
}
start.countDown();  //And off they go
0 голосов
/ 07 февраля 2012

Один из способов - создать ExecutorService с размером пула потоков, установленным в 1, и ждать в конце вашего метода run(), или поместить другой Runnable, который спит в его run(), в очередь между Runnables у вас уже есть.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...