简体   繁体   English

java CyclicBarrier未因重置而损坏

[英]java CyclicBarrier not broken with reset

I am trying to test BrokenBarrierException by resetting the cyclicbarrier in the middle of starting (awaiting) few parties (threads), please find the below sample code for the same.我正在尝试通过在启动(等待)几方(线程)的中间重置循环屏障来测试 BrokenBarrierException,请在下面找到相同的示例代码。

User class:用户类:

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 class: 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 ");
        }
    }
}

So, after running the main() above, I could get any exceptions and also "Barrier broken" also not printed.因此,在运行上面的 main() 之后,我可能会遇到任何异常,并且“屏障损坏”也没有打印出来。 The threads are simply waiting.线程只是在等待。

I have referred the CyclicBarrier API below link:我在下面的链接中提到了 CyclicBarrier API:

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

public void reset():公共无效重置():

Resets the barrier to its initial state.将障碍重置为其初始状态。 If any parties are currently waiting at the barrier, they will return with a BrokenBarrierException.如果任何一方当前正在屏障处等待,他们将返回 BrokenBarrierException。

But my above code doesn't seems to work according to the API description, so what is the problem with my above code and why it is NOT throwing BrokenBarrierException ?但是我上面的代码似乎没有根据 API 描述工作,那么我上面的代码有什么问题,为什么它没有抛出 BrokenBarrierException ?

Could you please help ?能否请你帮忙 ?

If you want exception thrown , you have to make sure barrier.reset();如果你想抛出异常,你必须确保barrier.reset(); executes after cb.await();cb.await();之后执行cb.await(); , but here System.out.println(name+" user started !!!! "); , 但这里System.out.println(name+" user started !!!! "); is a very costly statement which makes barrier.reset();是一个非常昂贵的语句,它使barrier.reset(); executes too early , you can add a sleep statement before barrier.reset();执行过早,可以在barrier.reset();之前添加sleep语句barrier.reset(); , say Thread.sleep(100); ,说Thread.sleep(100); . .

Doc of isBroken : isBroken文档:

true if one or more parties broke out of this barrier due to interruption or timeout since construction or the last reset, or a barrier action failed due to an exception;如果一个或多个参与方由于自构建或上次重置以来的中断或超时而突破此障碍,或者由于异常导致障碍操作失败,则为真; false otherwise.否则为假。

If you want it as broken , you can do something to the parties .如果你想把它弄坏,你可以给当事人做点什么。 You need remove reset to make threads awaiting .您需要删除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 ");
        }
    }
}

Short answer:简短的回答:

On reset the barrier loses the information of previous BrokenBarrierException (s).重置时屏障会丢失之前BrokenBarrierException (s) 的信息。 So any call to isBroken after reset will return false .因此,任何调用isBrokenreset将返回false

The javadoc specify this, although, not very clearly: javadoc 指定了这一点,虽然不是很清楚:

isBroken return: true if one or more parties broke out of this barrier due to interruption or timeout since construction or the last reset , or a barrier action failed due to an exception; isBroken return: true 如果一个或多个参与方由于自构造或上次重置以来的中断或超时而突破此屏障,或者由于异常导致屏障操作失败; false otherwise.否则为假。

Long answer:长答案:

You can see more clearly what happens if you look at source code of reset and isBroken :如果您查看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();
    }
}

You can see that the reference generation.broken holds the information about a broken barrier.您可以看到参考generation.broken包含有关已损坏障碍的信息。 But this is reinitialized to false on reset.但这在重置时被重新初始化为false

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM