Главная

Java

Многопоточность




Lock :

Интерфейс Lock API : существует с Java 1.5.
Базовый интерфейс из lock framework, предоставляющий более гибкий подход по ограничению доступа к ресурсам/блокам нежели при использовании synchronized. Так, при использовании нескольких локов, порядок их освобождения может быть произвольный. Плюс имеется возможность пойти по альтернативному сценарию, если лок уже кем то захвачен.

Различия между Lock и synchronized блоком :


методы интерфейса Lock:




интерфейс Condition :

@since Java 1.5
Интерфейс, который описывает альтернативные методы стандарным wait/notify/notifyAll. Объект с условием чаще всего получается из локов через метод lock.newCondition(). Тем самым можно получить несколько комплектов wait/notify для одного объекта




класс ReentrantLock :

Лок на вхождение. Только один поток может зайти в защищенный блок. Класс поддерживает «честную» (fair) и «нечестную» (non-fair) разблокировку потоков. При «честной» разблокировке соблюдается порядок освобождения потоков, вызывающих lock(). При «нечестной» разблокировке порядок освобождения потоков не гарантируется, но, как бонус, такая разблокировка работает быстрее. По умолчанию, используется «нечестная» разблокировка.


класс ReentrantReadWriteLock :

Очень часто используется в многопоточных сервисах и кешах, показывая очень хороший прирост производительности по сравнению с блоками synchronized. По сути, класс работает в 2-х взаимоисключающих режимах: много reader'ов читают данные в параллель и когда только 1 writer пишет данные.


класс StampedLock :

StampedLock представлен в Java 8.




Пример ReentrantLock:

одна блокировка сразу на два метода .
public class ReentrantLockExample {

    public static void main(String[] args) throws InterruptedException {
        Resource resource = new Resource(6, 14);

        MyThread thread1 = new MyThread(resource);
        thread1.setName("firstThread");
        MyThread thread2 = new MyThread(resource);

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.println(resource.getI());
        System.out.println(resource.getPhone());


    }


}

class MyThread extends Thread {
    private final Resource resource;

    MyThread(Resource res) {
        resource = res;
    }

    @Override
    public void run() {
        resource.incrementI();
    }
}

class Resource {
    private int i;

    public int getPhone() {
        return phone;
    }

    Resource(int i, int phone) {
        this.i = i;
        this.phone = phone;
    }

    private int phone;

    private final Lock lock = new ReentrantLock();

    void incrementI() {
        lock.lock();
        int iLocal = this.i;
        if (Thread.currentThread().getName().equals("firstThread")) {
            Thread.yield();
        }
        iLocal++;
        this.i = iLocal;

        incrementPhone();
    }

    void incrementPhone() {
        int phoneLocal = this.phone;
        if (Thread.currentThread().getName().equals("firstThread")) {
            Thread.yield();
        }
        phoneLocal++;
        this.phone = phoneLocal;
        lock.unlock();
    }

    int getI() {
        return i;
    }
}




Пример Condition:

Блокировка с условием .

public class ConditionsExample {

    private static Lock lock = new ReentrantLock();
    private static Condition condition = lock.newCondition();
    private static int bankAccount =0;

    public static void main(String[] args) {

        new AccountMinusMoney().start();
        new AccountPlusMoney().start();

    }

    static class  AccountPlusMoney extends Thread{
        @Override
        public void run() {
            lock.lock();
            bankAccount +=10;
            System.out.println("\n ------ прибавили 10 руб. \n");
            condition.signal();
            lock.unlock();
        }
    }

    static class  AccountMinusMoney extends Thread {
        @Override
        public void run() {
            if(bankAccount < 10){
                try {
                    lock.lock();
                    System.out.println("не можем списать деньги так как сумма на счету меньше 10 руб. =(");
                    System.out.println("... ждём ... другой поток ....  ");
                    condition.await();
                    lock.unlock();
                    System.out.println("... другой поток отработал ... продолжаем ! =) ");
                }catch (InterruptedException e){
                    e.printStackTrace();
                }

            }
            bankAccount -=10;
            System.out.println("\n ------ отняли 10 руб.\n");
            System.out.println();
        }
    }

}


Полезные ссылки: