【问题标题】:java CyclicBarrier not broken with resetjava CyclicBarrier 没有被重置破坏
【发布时间】:2016-10-08 08:34:59
【问题描述】:

我正在尝试通过在启动(等待)少数方(线程)中间重置循环障碍来测试 BrokenBarrierException,请查找以下示例代码。

用户类别:

public class User implements Runnable {
    
    private final String name;
    private final CyclicBarrier cb;
    
    public User(String name, CyclicBarrier cb) {
        this.name = name;
        this.cb = cb;
    }

    @Override
    public void run() {
        System.out.println(name+" user started !!!! ");
        try {
            cb.await();
        } catch (InterruptedException | BrokenBarrierException e) {
            System.out.println(e);
            e.printStackTrace();
        }
    }
}

CyclicBarrierTest 类:

public class CyclicBarrierTest {

    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(5);
        
        User user1 = new User("USER1", barrier);
        new Thread(user1).start();
        
        User user2 = new User("USER2", barrier);
        new Thread(user2).start();
        
        //Expected users are 5, but only 2 user threads started so far 
        // and resetting below which should throw barrier broken exception

        barrier.reset();
        
        if(barrier.isBroken()) {
            System.out.println("Barrier broken ");
        }
    }
}

所以,在运行上面的 main() 之后,我可能会遇到任何异常,而且“Barrier broken”也没有打印出来。线程只是在等待。

我在下面的链接中提到了 CyclicBarrier API:

https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CyclicBarrier.html

公共无效重置():

将屏障重置为其初始状态。如果有的话 各方目前正在屏障处等待,他们将返回 BrokenBarrierException。

但是根据 API 描述,我上面的代码似乎不起作用,那么上面的代码有什么问题,为什么它没有抛出 BrokenBarrierException ?

你能帮忙吗?

【问题讨论】:

    标签: java multithreading


    【解决方案1】:

    如果你想抛出异常,你必须确保barrier.reset();cb.await();之后执行,但是这里System.out.println(name+" user started !!!! ");是一个非常昂贵的语句,这使得barrier.reset();执行得太早,你可以在@之前添加一个睡眠语句987654325@,比如Thread.sleep(100);

    isBroken 的文档:

    如果一个或多个参与方由于自构造或上次重置后的中断或超时而突破此屏障,或者由于异常而导致屏障操作失败;否则为假。

    如果你想把它弄坏,你可以对当事人做点什么。您需要删除 reset 以使线程等待。

    public class User implements Runnable {
    
        private final String name;
        private final CyclicBarrier cb;
    
        public User(String name, CyclicBarrier cb) {
            this.name = name;
            this.cb = cb;
        }
    
        @Override
        public void run() {
            System.out.println(name+" user started !!!! ");
            try {
                cb.await(1,TimeUnit.SECONDS);
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            } catch (TimeoutException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
            System.out.println(name+" user ended !!!! ");
        }
    }
    
    
    public class CyclicBarrierTest {
    
        public static void main(String[] args) throws Exception {
            CyclicBarrier barrier = new CyclicBarrier(5);
    
            User user1 = new User("USER1", barrier);
            new Thread(user1).start();
    
            User user2 = new User("USER2", barrier);
            new Thread(user2).start();
    
    
            //Expected users are 5, but only 2 user threads started so far 
            // and resetting below which should throw barrier broken exception
            Thread.sleep(100);
    //        barrier.reset();
            Thread.sleep(1100);
            if(barrier.isBroken()) {
                System.out.println("Barrier broken ");
            }
        }
    }
    

    【讨论】:

    • 感谢您的回答,现在我可以注意到异常,但仍然没有执行 System.out.println("Barrier broken ") 行。
    【解决方案2】:

    简答:

    重置时,屏障会丢失以前的BrokenBarrierException(s) 的信息。所以在reset 之后对isBroken 的任何调用都将返回false

    javadoc 指定了这一点,虽然不是很清楚:

    isBroken return: true 如果一个或多个参与方由于构造或上次重置后的中断或超时而突破此屏障,或者由于异常而导致屏障操作失败;否则为假。

    长答案:

    如果你查看resetisBroken的源代码,你可以更清楚地看到发生了什么:

    public void reset() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            breakBarrier();   // break the current generation
            nextGeneration(); // start a new generation
        } finally {
            lock.unlock();
        }
    }
    
    private void breakBarrier() {
        generation.broken = true;
        count = parties;
        trip.signalAll();
    }
    
    private void nextGeneration() {
        // signal completion of last generation
        trip.signalAll();
        // set up next generation
        count = parties;
        generation = new Generation();
    }
    
    private static class Generation {
        boolean broken = false;
    }
    
    public boolean isBroken() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return generation.broken;
        } finally {
            lock.unlock();
        }
    }
    

    您可以看到引用 generation.broken 包含有关已损坏屏障的信息。但这会在重置时重新初始化为 false

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-30
      • 2011-09-19
      • 2019-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多