【问题标题】:CyclicBarrier misunderstandingCyclicBarrier 误解
【发布时间】:2014-12-07 20:54:59
【问题描述】:

我尝试从其中一个教程中使用 CyclicBarrier 运行示例: 当空打印机队列为 3 时,服务人员应填充空打印机。 但是当我运行代码时,似乎打印机在队列中填充了 2、3 或 4 台空打印机:

打印机 1 为空

Printer12 为空

Printer14 为空

Printer13 为空

填充[打印机1,打印机12,打印机14,打印机13]

打印机 2 为空

Printer7 为空

填充[打印机2,打印机7]

那么这个例子是错误的还是我对 CyclicBarrier 的理解?我认为队列应该正好是 3 个元素的大小。我应该在代码中添加什么来解决这个问题?提前致谢。

代码:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;

public class PrinterRecharger {
public static void main(String args[]) {
    ServiceMan serviceMan = new ServiceMan(3);

    for (int i = 0; i < 15; i++) {
        new Thread(new Printer(serviceMan, "Printer" + (i + 1))).start();
    }
}
}

class ServiceMan {

private CyclicBarrier queue;
private List<String> inQueue;

public ServiceMan(int hardWorking) {
    inQueue = new ArrayList<String>();
    queue = new CyclicBarrier(hardWorking, new Runnable() {
        @Override
        public void run() {
            System.out.println("Filling " + inQueue);
            inQueue.clear();
        }
    });
}

public void recharge(String name) {
    try {
        inQueue.add(name);
        queue.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (BrokenBarrierException e) {
        e.printStackTrace();
    }
}

}

class Printer implements Runnable {

private String name;
private Random rand;
private ServiceMan serviceMan;

public Printer(ServiceMan serviceMan, String name) {
    this.name = name;
    this.serviceMan = serviceMan;
    this.rand = new Random();
}

public void run() {
    try {
        while (true) {
            TimeUnit.SECONDS.sleep(rand.nextInt(10));
            System.out.println(name + " is empty");
            serviceMan.recharge(name);
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

}

【问题讨论】:

    标签: java concurrency java.util.concurrent cyclicbarrier


    【解决方案1】:

    您的代码在我可以立即看到的几个方面是线程不安全的,并且可能还有一些我错过了。您有数据竞争以及其他类型的竞争条件。

    • ArrayList 不是线程安全的类,但您可以在多个线程中使用它而没有同步。将列表包装成 Collections.synchronizedList() 以查看一些改进。

    • recharge()CyclicBarrier 的操作之间缺乏任何互斥。一个线程可以将一个项目添加到队列中,只是为了让它被操作清除。

    【讨论】:

    • inQueue = Collections.synchronizedList(new ArrayList());没有帮助。看起来应该做更多的改变。我可以在这里为互斥做什么?
    • recharge 和操作中定义private final Object lock = new Object() 和se synchronized(lock)。不过,请注意不要在持有锁时进入阻塞状态。
    • 方便多了!但我仍然可以在队列中看到 4 或 2 个项目(现在非常罕见)。我在屏障动作中为代码添加了同步(锁定),并在充值方法中将元素添加到队列中。但看起来应该添加其他内容。
    猜你喜欢
    • 2017-12-27
    • 2012-05-06
    • 2014-05-19
    • 2014-06-27
    • 2014-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-04
    相关资源
    最近更新 更多