Использование volatile для пропуска выполнения метода - PullRequest
0 голосов
/ 19 июня 2020

Я никогда не использовал volatile очень часто. Можно ли использовать его для пропуска выполнения метода, если его выполняет другой поток? Я думаю, что в приведенном ниже коде все еще возможно, что несколько потоков пройдут проверку и выполнят метод. Не так ли?

private static boolean volatile test = false;
...
    public void test() {
        if (test) {
            return;
        }
        test = true;
        try {
            System.out.println("test() started in Thread with ID " + Thread.currentThread().getId());
            Thread.sleep(10000);
            System.out.println("test() finished in Thread with ID " + Thread.currentThread().getId());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        test = false;
    }

Пример использования: метод может запускаться периодически, но в то же время он может запускаться пользователем вручную. Нет причин запускать его дважды один за другим, используя ключевое слово synchronized. Подскажите, пожалуйста, с volatile. В противном случае я не вижу причин для понимания этого, кроме собеседований :) Другие решения, не основанные на volatile, приветствуются.

1 Ответ

2 голосов
/ 19 июня 2020

Вы можете использовать volatile AtomicBoolean, например, для достижения ваших требований.

// default false so that first-thread that test() can enter the logic block
// AtomicBoolean's value is inherently volatile, so no need to declare volatile here
private static final AtomicBoolean test = new AtomicBoolean(false);   


public void test() {
    if (test.compareAndSet(false, true)) {  // check if the test if previously false and if so update it to true
        try {
            System.out.println("test() started in Thread with ID " + Thread.currentThread().getId());
            Thread.sleep(10000);
            System.out.println("test() finished in Thread with ID " + Thread.currentThread().getId());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            test.set(false); // executing thread now re-sets the test value
        }
    }
}
...