等待第一个方法在所有线程中执行直到执行第二个

Wait till first method is executed in all threads till execute second

我有一个小的演示代码,其中有一个 Bean class 和 BeanRegister class。 Bean class 有两个方法,分别是 preInit()postInit()。 BeanRegister 是一个线程 class,它以 Bean class 作为字段。这是我的代码:

public static void main(String[] args) {
    Bean beanA = new Bean();

    BeanRegister beanRegister1 = new BeanRegister(beanA);
    BeanRegister beanRegister2 = new BeanRegister(beanA);

    beanRegister1.start();
    beanRegister2.start();
}

private static class BeanRegister extends Thread {
    private final Bean bean;

    public BeanRegister(Bean bean) {
        this.bean = bean;
    }

    @Override
    public void run() {
        try {
            bean.preInit();
            bean.postInit();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

private static class Bean {

    public void preInit() throws InterruptedException {
        Thread.sleep(new Random().nextInt(1000) * 5);
        System.out.println("PreInit +" + Thread.currentThread().getName());
    }

    public void postInit() throws InterruptedException {
        System.out.println("PostInit +" + Thread.currentThread().getName());
    }
}

我遇到的问题是锁定。我想在所有线程中锁定 postInit(),在那些线程中 preInit() 方法的执行未完成之前。所以,当所有线程都执行完preInit(),那么我要让线程执行postInit()。知道如何以正确的方式做到这一点吗?

您可以使用在所有线程之间共享的 CountDownLatch

先讲一些理论:什么是 CountDownLatch

这是一个非常简单的并发实用程序,您可以使用某个整数(假设为 N)进行初始化。然后它会为您提供两种方法:

  • countdown() => 每次调用
  • 都会减少到 N-1
  • await() => 它将停止当前线程,直到倒计时计数为零(如果需要,您可以指定超时)。

当然,这个class的最大优点是为你处理了竞争条件(当你从某个线程调用countdown()await()时,你保证其他线程将在您不处理任何内存屏障的情况下看到发生了什么。

现在,根据您的代码,您首先制作 BeanpreInitpostInit 方法,在参数中采用 CountDownLatch

private static class Bean {

    public void preInit(CountDownLatch latch) throws InterruptedException {
        Thread.sleep(new Random().nextInt(1000) * 5);
        System.out.println("PreInit +" + Thread.currentThread().getName());
        latch.countDown(); //<-- each time one preInit ends, decrease the countdown by 1
    }

    public void postInit(CountDownLatch latch) throws InterruptedException {
        latch.await(); //<-- even if you're called here, wait until when the countdown is at zero before starting execution
        System.out.println("PostInit +" + Thread.currentThread().getName());
    }
}

具体来说,preInit 会倒数,而 postInitawait 在实际开始前倒数为零。

然后,在您的调用函数中创建一个 new CountDownLatch(2)(其中 2 是独立线程的数量),您只需将其压入调用堆栈:

public static void main(String[] args) {
    Bean beanA = new Bean();

    CountDownLatch latch = new CountDownLatch(2);
    BeanRegister beanRegister1 = new BeanRegister(beanA, latch);
    BeanRegister beanRegister2 = new BeanRegister(beanA, latch);

    beanRegister1.start();
    beanRegister2.start();
}

private static class BeanRegister extends Thread {
    private final Bean bean;
    private final CountDownLatch latch;

    public BeanRegister(Bean bean, CountDownLatch latch) {
        this.bean = bean;
        this.latch = latch;
    }

    @Override
    public void run() {
        try {
            bean.preInit(latch);
            bean.postInit(latch);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

示例输出:

PreInit +Thread-1
PreInit +Thread-0
PostInit +Thread-1
PostInit +Thread-0

Process finished with exit code 0