当前位置: 代码迷 >> java >> java.util.concurrent.BrokenBarrierException的原因
  详细解决方案

java.util.concurrent.BrokenBarrierException的原因

热度:118   发布时间:2023-07-25 19:51:12.0

我正在学习循环障碍。

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

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

请帮忙了解我的错误

PS

有时候在输出中我看到了以下行:

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

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

PPS

输出样本:

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)

购买力平价

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

您运行操作会抛出ConcurrentModificationException

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

PS:你在ArrayList获得了超过5个元素,因为没有什么可以防止它被改变。

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

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

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

  1. ProductParser.run()限制为仅循环到PRODUCT_TRESHOLD迭代。
  2. 通过将parsedProducts线程更改为来使其成为安全的线程

最后,只是你的代码的一般性评论:这感觉不对,以我main()创造了多个工作线程共享一个实例,并且具有共享实例强加给线程的屏障。 我想我更习惯于看到一个障碍和屏障动作被父线程引入并强加给它的所有子线程,就像Java 的示例一样。

  相关解决方案