Synchronization

Проработать

  1. Синхронизация потоков. Оператор synchronized в Java

Способы синхронизация

  1. wait/notify
  2. synchronized
  3. Thread.join
  4. Lock
  5. Semaphore

Synchronized

synchronized - это ключевое слово, которое позволяет заблокировать доступ к методу или части кода, если его уже использует другой поток. По принципу Mutex. Все остальные потоки которые попробуют получить монитор, станут wait(). После выхода из монитора вызывается - notify().

Применения

  1. Для блока кода - если не нужно синхронизировать весь метод. Нужно передавать объект в качестве монитора. Обычно передается this, это делает синхронизацию по текущему объекту.
    private Object key = new Object();
    
    synchronized (key) {
        System.out.println("Hi I'm synchronized block!");
    }
                    
  2. Для метода. В качестве объекта будет текущая ссылка на объект(this).
    synchronized void myMethod() {
        System.out.println("Hi I'm synchronized method!");
    }
                    

    Можно воспринимать так:

    void myMethod() {
        synchronized(this) {
          System.out.println("Hi I'm synchronized method!");
        }
    }
                    

    Для статического метода передается .class. По этому статическая блокировка и не статическая на одном классе не будут блокировать друг друга:

    static void myMethod() {
        synchronized(MyObject.class) {
          System.out.println("Hi I'm synchronized method!");
        }
    }
                    

Минус synchronized - другие потоки вынуждены ждать, пока нужный объект или метод освободится "bottle neck".

Volatile

volatile - ключевое слово для переменной. Указывает что переменная может быть изменена многими потоками.

  1. Не блокирует другие потоки.
  2. Не используется для инкремента.
  3. Она всегда будет атомарно read/write(не про атомарность измений). Даже если это 64-битные double или long. Несколько потоков не должны менять(edit) значение.
  4. Java-машина не будет помещать ее в кэш потоков(кеш процессора). Так что ситуация, когда 10 потоков работают со своими локальными копиями этой переменной - исключена.

Условия использования volatile:

Пример

public class VolatileExample {
    private static volatile boolean flag = false;

    public static void main(String[] args) {
        // create and start a new thread
        new Thread(() -> {
            while (!flag) {
                // do some work
            }
            System.out.println("Thread finished");
        }).start();

        // set the flag to true after a delay
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        flag = true;
    }
}
        

Atomic

Часто используется как счетчик. Предотвращает Race conditions

Compare and Swap(CAS) - паттерн который используют Atomic классы. Оптимистическая блокировка.

Виды:

  1. AtomicBoolean
  2. AtomicInteger
  3. AtomicLong
  4. AtomicIntegerArray
  5. AtomicLongArray
  6. AtomicReference
  7. AtomicReferenceArray
  8. AtomicStampedReference

Методы:

  1. increment()
  2. incrementAndGet()
  3. getCounter()