在指定的超时后从一个线程执行多个Runnable

时间:2012-02-07 17:10:17

标签: java multithreading concurrency

我想安排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 个答案:

答案 0 :(得分:2)

经过一些刺耳的评论之后,我想我已经开始明白你在做什么,看起来像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 :(得分:1)

最好的办法是使用ScheduledThreadExecutor。您可以使用一个线程池创建它:

ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1);

然后查看schedulescheduleAtFixedRate方法。

答案 2 :(得分:0)

一种方法是创建一个ExecutorService,并将线程池大小设置为1并在run()方法结束时等待,或者将另一个Runnable放入其中run() {{1}} 1}}进入你已经拥有的Runnables之间的队列。

Link虽然提出了一个很好的问题,但实际上你将按顺序运行这些任务。

答案 3 :(得分:0)

如果您希望一次性运行它们而不是按顺序运行它们,那么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