Синглтон, потоки и синхронизация - PullRequest
0 голосов
/ 02 июня 2018

Я слежу за книгой Head First Design Patterns (ГЛАВА 5, Шаблон Singleton).

Они говорят о перекрытии потока в методе getInstance(), когда ключевое слово synchronized не соответствуетused.

Как я могу увидеть на экране разницу в поведении потоков?

  public class ChocolateBoiler {    

        private boolean empty;
        private boolean boiled;
        private static ChocolateBoiler chocolateBoilerInstance;

        public ChocolateBoiler() {
            empty = true;
            boiled = false;
        }

        public static (synchronized) ChocolateBoiler getInstance() {
            if (chocolateBoilerInstance == null) {
                chocolateBoilerInstance = new ChocolateBoiler();
            }
            return chocolateBoilerInstance;
        }

        public void fill() {
            if (isEmpty()) {
                empty = false;
                boiled = false;
                // fill the boiler with a milk/chocolate mixture
            }
        }

        public void drain() {
            if (!isEmpty() && isBoiled()) {
                // drain the boiled milk and chocolate
                empty = true;
            }
        }

        public void boil() {
            if (!isEmpty() && !isBoiled()) {
                // bring the contents to a boil
                boiled = true;
            }
        }

        public boolean isEmpty() {
            return empty;
        }

        public boolean isBoiled() {
            return boiled;
        }

        public static void main(String[] args) {

            ChocolateBoiler boiler = ChocolateBoiler.getInstance();
            boiler.fill();
            boiler.boil();
            boiler.drain();
        }
 }

1 Ответ

0 голосов
/ 02 июня 2018

Ваш пример слишком сложен.Я создал другой, более простой, посмотрите код ниже.Если вы запустите его как есть, вы увидите строки в консоли, где 0 и 1 смешаны, как показано ниже:

11111111111111111111000000000000111111111111111111
11111111111111111111110000000000001111111111111111

Причина в том, что два потока изменяют одну и ту же переменную экземпляра "value" в синглтонеодновременно.

Теперь добавьте слово «synchronized» в оба метода «setValue» и «printValue» и запустите его снова.Вы увидите, что все строки состоят только из 0 или 1.Они больше не смешиваются.

00000000000000000000000000000000000000000000000000
11111111111111111111111111111111111111111111111111

Причина в том, что в любой момент только один из потоков изменяет переменную, поскольку «синхронизированный» предотвращает одновременный доступ к объекту-одиночке из разных потоков.

Вот код:

public class Main {

    public static class Singleton {

        private static Singleton instance = new Singleton();

        public static Singleton getInstance() {
            return instance;
        }

        private char[] value = new char[50];

        private Singleton() {
        }

        public void printValue() {
            for (int i = 0; i < value.length; i++) {
                System.out.print(value[i]);
            }
            System.out.println();
        }

        public void setValue(String newValue) {
            for (int i = 0; i < newValue.length() && i < value.length; i++) {
                value[i] = newValue.charAt(i);
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    // Ignore
                }
            }
        }

    }

    public static void main(String[] args) {
        final int MAX = 100000;

        Thread thread1 = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < MAX; i++) {
                    Singleton.getInstance().setValue("00000000000000000000000000000000000000000000000000");
                    yield();
                }
            }
        };

        Thread thread2 = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < MAX; i++) {
                    Singleton.getInstance().setValue("11111111111111111111111111111111111111111111111111");
                    yield();
                }
            }
        };

        Thread thread3 = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < MAX; i++) {
                    System.out.printf("%5d:   ", i);
                    Singleton.getInstance().printValue();
                    yield();
                }
            }
        };

        thread1.start();
        thread2.start();
        thread3.start();
    }

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