CyclicBarrier误解

时间:2014-10-13 10:11:28

标签: java concurrency java.util.concurrent cyclicbarrier

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

  

Printer1为空

     

Printer12为空

     

Printer14为空

     

Printer13为空

     

填写[Printer1,Printer12,Printer14,Printer13]

     

Printer2为空

     

Printer7为空

     

填写[Printer2,Printer7]

示例错误或我对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();
    }
}

}

1 个答案:

答案 0 :(得分:0)

您的代码在某种程度上是线程不安全的,我可以立即看到,还有一些我错过了。您有数据竞赛以及其他类型的竞争条件。

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

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