почему DCL использует volatile, а не использует final? i код запускает тот же эффект - PullRequest
0 голосов
/ 26 апреля 2018
package test1;

import java.util.Random;

public class OneInstanceService {
    // use volatile or final,them has same effect,
    // but difference volatile or final in DCL demo?
    public int i_am_has_state;

    private static OneInstanceService test;

    private OneInstanceService() {
        i_am_has_state = new Random().nextInt(200) + 1;
    }

    public static OneInstanceService getTest1() {
        if (test == null) {
            synchronized (OneInstanceService.class) {
                if (test == null) {
                    test = new OneInstanceService();
                }
            }
        }
        return test;
    }

    public static void reset() {
        test = null;
    }

}


//----------------------------------------
package test1;

import java.util.concurrent.CountDownLatch;

public class Test1 {
    public static void main(String[] args) throws InterruptedException {
        for (;;) {
            CountDownLatch latch = new CountDownLatch(1);
            CountDownLatch end = new CountDownLatch(100);
            for (int i = 0; i < 100; i++) {
                Thread t1 = new Thread() {
                    @Override
                    public void run() {
                        try {
                            latch.await();
                            OneInstanceService one = OneInstanceService.getTest1();
                            if (one.i_am_has_state == 0) {
                                System.out.println("one.i_am_has_state == 0 process exit");
                                System.exit(0);
                            }
                            end.countDown();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                };
                t1.start();
            }
            latch.countDown();
            end.await();
            OneInstanceService.reset();
        }
    }
}

только использовать:

public int i_am_has_state;

результат выполнения:

System.out.println("one.i_am_has_state == 0 process exit");
System.exit(0);

, но изменить нижнюю часть кода:

volatile public int i_am_has_state;

или

final public int i_am_has_state;

нет нижнего кода прогона:

System.out.println("one.i_am_has_state == 0 process exit");
System.exit(0);

Вопрос в том, что: DCL использует окончательное состояние, DCL использует окончательное значение, изменяемое в порядке

, так что в DCL окончательная и изменчивая разница?

большое спасибо!

Ответы [ 2 ]

0 голосов
/ 30 апреля 2018

final и volatile не могут идти вместе, потому что они целенаправленно противоположны.

либо у вас есть статическое поле, инициализированное один раз при инициализации класса:

static final Object x;
static {
    x = ...
}

, либо у вас есть изменяемое статическое поле, котороеможно установить несколько потоков (ваш случай).

Он должен быть изменчивым, чтобы идиома двойной проверки работала (с новой изменчивой семантикой, начиная с jdk 1.5).С тех пор у volatile есть барьеры памяти, предотвращающие переупорядочение команд с другими переменными, что каким-то образом (я не могу вспомнить этот материал сейчас ...) заставляет работать некрасивый DCL снова ... но не делает его менее уродливым.

(мне никогда не нужно было использовать DCL; без DCL синхронизация по-прежнему практически не выполняется, поскольку if(x==null) очень быстрый.)

0 голосов
/ 26 апреля 2018

спасибо всем, дно не отвечает.

Я изменяю код:

package test1;

import java.util.Random;

public class OneInstanceService {
    final public int i_am_has_state;

    volatile private static OneInstanceService test;

    private OneInstanceService() {
        i_am_has_state = new Random().nextInt(200) + 1;
    }

    public static OneInstanceService getTest1() {
        if (test == null) {
            synchronized (OneInstanceService.class) {
                if (test == null) {
                    test = new OneInstanceService();
                }
            }
        }
        return test;
    }

    public static void reset() {
        test = null;
    }

}

Только что внезапно вдохновил, код настолько совершенен?Я думаю, что я действительно запутался.

shmosel: Простите за то, что я не форматировал код и линию высоты, большое спасибо.

...