ReentrantLock в качестве замены для CountdownLatch - PullRequest
0 голосов
/ 09 января 2020

У меня есть myCountDownLatch (который работает, как и ожидалось):

public static void myCountDownLatch() {

    CountDownLatch countDownLatch = new CountDownLatch(1);
    Thread t = new Thread(() ->
    {
        try {
            log.info("CountDownLatch: in thread..");
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        countDownLatch.countDown();
    });
    t.start();
    try {
        countDownLatch.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    log.info("CountDownLatch: out thread..");
}

Я пытаюсь понять разницу CountdownLatch и ReentrantLock и попытался переписать myCountDownLatch с помощью ReentrantLock вместо CountdownLatch:

public static void myRentrantLock() {

    ReentrantLock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    Thread t = new Thread(() ->
    {
        try {
            log.info("ReentrantLock: in thread..");
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });

    lock.lock();
    t.start();
    lock.unlock();

    log.info("ReentrantLock: out thread..");
}

Я хочу остановить основной поток только до тех пор, пока Thread t не завершится с использованием ReentrantLock вместо CountDownLatch.

Однако myRentrantLock не ведет себя так, как мой myCountDownLatch. Почему?

1 Ответ

1 голос
/ 09 января 2020

Вы не можете заменить защелку обратного отсчета на ReentrantLock, которая является инструментом для взаимного исключения и уведомления, но вы можете использовать ReentrantLock для реализации аналогичной функциональности.

Может выглядеть так:

public class MyLatch {
    final ReentrantLock lock = new ReentrantLock();
    final Condition zeroReached = lock.newCondition();
    int remaining;

    MyLatch(int count) {
        if(count < 0) throw new IllegalArgumentException();
        remaining = count;
    }
    public void await() throws InterruptedException {
        lock.lock();
        try {
            while(remaining != 0) zeroReached.await();
        }
        finally {
            lock.unlock();
        }
    }
    public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
        lock.lock();
        try {
            if(remaining == 0) return true;
            long deadLine = System.nanoTime() + unit.toNanos(timeout);
            while(remaining != 0) {
                final long remainingTime = deadLine - System.nanoTime();
                if(remainingTime <= 0) return false;
                zeroReached.await(remainingTime, TimeUnit.NANOSECONDS);
            }
            return true;
        }
        finally {
            lock.unlock();
        }
    }
    public void countDown() {
        lock.lock();
        try {
            if(remaining > 0 && --remaining == 0) zeroReached.signalAll();
        }
        finally {
            lock.unlock();
        }
    }
    public long getCount() {
        lock.lock();
        try {
          return remaining;
        }
        finally {
            lock.unlock();
        }
    }
}

ReentrantLock защищает внутреннее состояние, которым является поле remaining. Связанный Condition zeroReached используется для того, чтобы потоки, ожидающие, пока поле remaining станет нулевым.

Это можно использовать так же, как встроенный CountDownLatch:

public class MyLatchTest {
    public static void main(String[] args) {
        int num = 10;
        MyLatch countDownLatch = new MyLatch(num);
        for(int i = 0; i < num; i++) {
            Thread t = new Thread(() ->
            {
                try {
                    System.out.println("CountDownLatch: in thread..");
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("CountDownLatch: one thread finished..");
                countDownLatch.countDown();
            });
            t.start();
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("CountDownLatch: out thread..");
    }
}

Обратите внимание, что здесь вам не нужен явный Lock, функция блокировки intrinsi c в Java также будет работать:

public class MyLatch {
    int remaining;

    MyLatch(int count) {
        if(count < 0) throw new IllegalArgumentException();
        remaining = count;
    }
    public synchronized void await() throws InterruptedException {
        while(remaining != 0) wait();
    }
    public synchronized boolean await(long timeout, TimeUnit unit) throws InterruptedException {
        if(remaining == 0) return true;
        long deadLine = System.nanoTime() + unit.toNanos(timeout);
        while(remaining != 0) {
            long remainingTime = deadLine - System.nanoTime();
            if(remainingTime <= 0) return false;
            wait(remainingTime / 1_000_000, (int)(remainingTime % 1_000_000));
        }
        return true;
    }
    public synchronized void countDown() {
        if(remaining > 0 && --remaining == 0) notifyAll();
    }
    public synchronized long getCount() {
        return remaining;
    }
}

Но в любом случае встроенный CountDownLatch более эффективен ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...