首先重新处理跳过的项目的Java优先级队列

时间:2017-08-10 07:41:11

标签: java multithreading synchronization

假设我们有一个JobItem,其中包含两个字段jobIddbTableName。 我们还有一个4的Executor线程池。

最初,执行程序将从队列中运行第一个作业项。 如果后续队列头具有相同的dbTableName表tableA,我想获得下一个队列项下一个不具有相同dbTableName的作业项并首先执行它。

由于第一份工作可能需要很长时间,我们可能会在我们再次处理tableA之前使用其他表处理多个其他工作项

我们希望确保tableA的所有作业都按顺序处理。

我有另一个列表,用于保存当前正在运行的作业列表。

目前,我看到只有通过迭代队列项并检查当前正在运行的作业列表才能提供此类功能。

有没有更好的方法来实现这一目标?

谢谢

2 个答案:

答案 0 :(得分:0)

对于每个表,您需要一个具有单独的作业输入队列的串行执行程序。 Executor从队列中获取作业并按顺序运行它们。 串行执行器可以通过两种方式实现:作为线程或作为actor。线程实现更简单但需要更多内存。 Actor实现需要对线程库的额外依赖。在您的情况下,演员库可以像https://github.com/rfqu/CodeSamples/blob/master/src/simpleactor/SimpleActor.java

一样简单

答案 1 :(得分:0)

您可以创建具有队列的线程池和工作线程。

public void execute(Runnable command) {

        final int key= command.getKey();
         //Some code to check if it is runing
        final int index = key != Integer.MIN_VALUE ? Math.abs(key) % size : 0;
        workers[index].execute(command);
    }

工人代码

 private final AtomicBoolean scheduled = new AtomicBoolean(false);

    private final BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>(maximumQueueSize);

    public void execute(Runnable command) {
        long timeout = 0;
        TimeUnit timeUnit = TimeUnit.SECONDS;
        if (command instanceof TimeoutRunnable) {
            TimeoutRunnable timeoutRunnable = ((TimeoutRunnable) command);
            timeout = timeoutRunnable.getTimeout();
            timeUnit = timeoutRunnable.getTimeUnit();
        }

        boolean offered;
        try {
            if (timeout == 0) {
                offered = workQueue.offer(command);
            } else {
                offered = workQueue.offer(command, timeout, timeUnit);
            }
        } catch (InterruptedException e) {
            throw new RejectedExecutionException("Thread is interrupted while offering work");
        }

        if (!offered) {
            throw new RejectedExecutionException("Worker queue is full!");
        }

        schedule();
    }

    private void schedule() {
        //if it is already scheduled, we don't need to schedule it again.
        if (scheduled.get()) {
            return;
        }

        if (!workQueue.isEmpty() && scheduled.compareAndSet(false, true)) {
            try {
                executor.execute(this);
            } catch (RejectedExecutionException e) {
                scheduled.set(false);
                throw e;
            }
        }
    }

    public void run() {
        try {
            Runnable r;
            do {
                r = workQueue.poll();
                if (r != null) {
                    r.run();
                }
            }
            while (r != null);
        } finally {
            scheduled.set(false);
            schedule();
        }
    }