java.util.concurrent.BrokenBarrierException

时间:2015-08-07 16:02:59

标签: java multithreading

我正在学习循环障碍。

我正在尝试编写代码示例:

public class Main {

    public static final int PARSER_COUNT = 15;
    public static final int PRODUCT_TRESHOLD = 5;

    public static void main(String args[]) {
        ProductImporter productImporter = new ProductImporter(PRODUCT_TRESHOLD);

        for (int i = 0; i < PARSER_COUNT; i++) {
            new Thread(new ProductParser(productImporter, "Parser" + (i + 1))).start();
        }
    }
}

class ProductImporter {

    private CyclicBarrier barrier;
    private List<String> parsedProducts;

    public ProductImporter(int productTreshold) {
        parsedProducts = new ArrayList<String>();
        barrier = new CyclicBarrier(productTreshold, new Runnable() {
            @Override
            public void run() {
                System.out.println("start import " + parsedProducts);
                parsedProducts.clear();
            }
        });
    }

    public void recharge(String name) {
        try {
            parsedProducts.add(name);
            /*System.out.println("Added product to importList#"+parsedProducts.size());*/
            barrier.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }

}

class ProductParser implements Runnable {

    private String name;
    private Random rand;
    private ProductImporter productImporter;
    private int counter = 0;

    public ProductParser(ProductImporter productImporter, String name) {
        this.name = name;
        this.productImporter = productImporter;
        this.rand = new Random();
    }

    public void run() {
        try {
            while (true) {
                Thread.sleep(rand.nextInt(12));
                System.out.println(name + " parsed product#" + counter);
                productImporter.recharge(name + "#" + (counter++));
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

但我得到java.util.concurrent.BrokenBarrierException

请帮助理解我的错误

P.S。

有时候在输出中我会看到有些行:

start import [Parser7, Parser4, Parser9, Parser10, Parser2, Parser13, Parser6]

预期结果 - 包含5个元素的数组

P.P.S。

输出样本:

start import [Parser13#21, Parser15#28, Parser12#22, Parser6#19, Parser8#27]
Parser9 parsed product#23
Parser1 parsed product#19
Parser15 parsed product#29
Parser14 parsed product#23
Parser11 parsed product#22
start import [Parser9#23, Parser1#19, Parser15#29, Parser14#23, Parser11#22]
Parser12 parsed product#23
Parser8 parsed product#28
Parser4 parsed product#25
Parser13 parsed product#22
Parser5 parsed product#23
start import [Parser12#23, Parser8#28, Parser4#25, Parser13#22, Parser5#23]
Parser7 parsed product#23
Parser3 parsed product#26
Parser6 parsed product#20
Parser14 parsed product#24
Parser10 parsed product#25
start import [Parser7#23, Parser3#26, Parser6#20, Parser14#24, Parser10#25]
Parser2 parsed product#24
Parser4 parsed product#26
Parser8 parsed product#29
Parser1 parsed product#20
Parser5 parsed product#24
Parser13 parsed product#23
start import [Parser2#24, Parser4#26, Parser8#29, Parser1#20, Parser5#24]
Parser5 parsed product#25
Parser9 parsed product#24
Parser11 parsed product#23
Parser7 parsed product#24
start import [Parser5#25, Parser9#24, Parser11#23, Parser7#24]
Parser10 parsed product#26
Parser3 parsed product#27
Parser1 parsed product#21
Parser13 parsed product#24
Parser7 parsed product#25
start import [Parser10#26, Parser3#27, Parser1#21, Parser13#24, Parser7#25]
Parser2 parsed product#25
Parser10 parsed product#27
Parser7 parsed product#26
Parser15 parsed product#30
Parser12 parsed product#24
start import [Parser2#25, Parser10#27, Parser7#26, Parser15#30, Parser12#24]
Parser6 parsed product#21
Parser14 parsed product#25
Parser11 parsed product#24
Parser5 parsed product#26
Parser13 parsed product#25
Parser1 parsed product#22
Parser4 parsed product#27
Parser11 parsed product#25
Parser11 parsed product#26
Exception in thread "Thread-12" java.util.concurrent.BrokenBarrierException
    at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:207)
    at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:362)
    at lection2.task3.ProductImporter.recharge(Main.java:46)
    at lection2.task3.ProductParser.run(Main.java:74)
    at java.lang.Thread.run(Thread.java:745)
java.util.concurrent.BrokenBarrierException
    at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:250)
    at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:362)
    at lection2.task3.ProductImporter.recharge(Main.java:46)
    at lection2.task3.ProductParser.run(Main.java:74)
    at java.lang.Thread.run(Thread.java:745)
java.util.concurrent.BrokenBarrierException
    at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:250)
    at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:362)
    at lection2.task3.ProductImporter.recharge(Main.java:46)
    at lection2.task3.ProductParser.run(Main.java:74)
    at java.lang.Thread.run(Thread.java:745)
java.util.concurrent.BrokenBarrierException
    at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:207)
    at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:362)
    at lection2.task3.ProductImporter.recharge(Main.java:46)
    at lection2.task3.ProductParser.run(Main.java:74)
    at java.lang.Thread.run(Thread.java:745)
java.util.concurrent.BrokenBarrierException
    at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:207)
    at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:362)
    at lection2.task3.ProductImporter.recharge(Main.java:46)
    at lection2.task3.ProductParser.run(Main.java:74)
    at java.lang.Thread.run(Thread.java:745)
java.util.concurrent.BrokenBarrierException
    at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:250)
    at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:362)
    at lection2.task3.ProductImporter.recharge(Main.java:46)
    at lection2.task3.ProductParser.run(Main.java:74)
    at java.lang.Thread.run(Thread.java:745)
java.util.concurrent.BrokenBarrierException
    at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:250)
    at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:362)
    at lection2.task3.ProductImporter.recharge(Main.java:46)
    at lection2.task3.ProductParser.run(Main.java:74)
    at java.lang.Thread.run(Thread.java:745)
java.util.concurrent.BrokenBarrierException
    at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:207)
    at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:362)
    at lection2.task3.ProductImporter.recharge(Main.java:46)
    at lection2.task3.ProductParser.run(Main.java:74)
    at java.lang.Thread.run(Thread.java:745)

P.P.P.S

如果让睡眠间隔更好 - 它运作良好。

2 个答案:

答案 0 :(得分:2)

您执行操作抛出ConcurrentModificationException

因为ArrayList不是合适的容器。使用synchronized块保护对它的访问或使用Vector等线程安全容器。

PS:你的ArrayList中有5个元素,因为没有任何东西可以防止它被改变。

答案 1 :(得分:0)

查看CyclicBarrier构造函数的docs,它说:

  

创建一个新的CyclicBarrier,当给定数量的聚会(线程)正在等待它时将跳闸,并且当屏障被触发时执行给定的屏障操作,由进入屏障的最后一个线程执行。

因此,您的ProductImporter.recharge和屏障操作之间可能存在竞争条件,前者尝试添加到您的parsedProducts数组列表,后者尝试清除它。要尝试的两个简单修复方法是:

  1. ProductParser.run()限制为仅PRODUCT_TRESHOLD次迭代。
  2. parsedProducts线程更改为java.util.concurrent.CopyOnWriteArrayList
  3. ,使其保持安全

    最后,只是关于你的代码的一般性评论:main()创建一些工作线程来共享一个实例并且让该共享实例对线程。我想我更习惯看到父线程在其所有子线程上引入和强加的屏障和屏障操作,如Java doc中的示例。