有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java有没有办法让两个线程不从共享集合中获取相同的项?

我有一个有3个线程的程序。一个线程用于向共享集合中添加项目,其余两个线程用于从集合中删除项目并对其进行处理

我创建了一个用于添加的Runnable。看起来是这样的:

public class Adder implements Runnable {

    private static final Integer MAX_NO = 1000; // I wanted this to be Integer.MAX_VALUE
    private final List<Integer> shared;
    private final AtomicBoolean isAddingDone;

    public Adder(final List<Integer> shared, final AtomicBoolean isAddingDone) {
        this.shared= shared;
        this.isAddingDone = isAddingDone;
    }

    @Override
    public void run() {
        for (int i = 0; i < MAX_NO; i++) {
            shared.add(i);
        }
        isAddingDone.set(true);
    }

}

我创建了另一个Runnable,用于从共享集合中删除一个项

public class Remover implements Runnable {

    private final int id;
    private boolean stopRequested = false;
    private final List<Integer> shared;
    private final AtomicBoolean isAddingDone;

    public Remover(final int id, final List<Integer> shared, final AtomicBoolean isAddingDone) {
        this.id = id;
        this.shared = shared;
        this.isAddingDone = isAddingDone;
    }

    public synchronized void requestStop() {
        this.stopRequested = true;
    }

    public synchronized boolean isStopRequested() {
        return this.stopRequested;
    }

    @Override
    public void run() {
        System.out.println("Starting Remover" + id + "...");
        while (!isStopRequested()) {
            if (shared.isEmpty() && isAddingDone.get()) {
                this.requestStop();
            } else {
                final Integer value = shared.get(0);
                System.out.println("Remover" + this.id + " retrieved " + value + ". Removing...");
                shared.remove(value);
                // processing of value here
            }
        }
    }

}

以下是主要方法:

public static void main(String[] args) {
    final List<Integer> shared = new Vector<>();
    final AtomicBoolean isAddingDone = new AtomicBoolean(false);

    final Runnable tAdder = new Adder(shared, isAddingDone);
    final Runnable tRemover0 = new Remover(0, shared, isAddingDone);
    final Runnable tRemover1 = new Remover(1, shared, isAddingDone);

    Thread t1 = new Thread(tAdder, "Thread-Adder");
    t1.start();

    Thread r0 = new Thread(tRemover0, "Thread-Remover0");
    r0.start();

    Thread r1 = new Thread(tRemover1, "Thread-Remover1");
    r1.start();
}

我在运行程序时没有遇到任何错误,但我注意到,在某个时刻,两个线程都在检索同一项

Starting Remover0...
Starting Remover1...
Remover1 retrieved 0. Removing...
Remover0 retrieved 0. Removing...
Remover1 retrieved 1. Removing...
Remover0 retrieved 1. Removing...
Remover1 retrieved 2. Removing...
Remover1 retrieved 3. Removing...

有没有办法让两个去除器不处理同一个项目?我尝试使用迭代器,但在运行时,我遇到了ConcurrentModificationException


共 (1) 个答案

  1. # 1 楼答案

    shared.isEmpty()shared.get(0)shared.remove(value)不会以原子方式发生,因此不能保证列表在这段时间内没有变化

    如果要在线程之间通信,请使用BlockingQueue,如果有可用的项目,则使用poll()从中删除。这允许您将isEmpty()getremove组合成单个原子动作

    // From the while loop inside Remover:
                Integer value = shared.poll();
                if (value == null /* indicates the queue was empty when you looked. */
                        && isAddingDone.get()) {
                    this.requestStop();
                } else {
                    System.out.println("Remover" + this.id + " retrieved " + value + ". Removing...");
                    // No need to remove, you already did.
                    // processing of value here
                }