programming java - lection 06 - multithreading - lavrentyev fedor

28
6. Многопоточность Программирование на Java Федор Лаврентьев МФТИ, 2016

Upload: fedor-lavrentyev

Post on 14-Jan-2017

140 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

6. МногопоточностьПрограммирование на Java

Федор ЛаврентьевМФТИ, 2016

Page 2: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

Потоки

Page 3: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

Процесс и поток• Процесс• Выделенная память• Процессорное время расходуется потоками• Порождается через fork• Общается с другими процессами через сокеты и shared memory

• Поток• Общая память процесса• Собственный кеш• Расходует процессорное время• Порождается внутри процесса• Общается с другими потоками через общую память процесса

Page 4: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

java.lang.Thread• start(), run()• static sleep(), static yield()• stop(), destroy()• interrupt(), isInterrupted(), static interrupted()• setDaemon(), isDaemon()• join()• getState():

• NEW• RUNNABLE• BLOCKED• WAITING, TIMED_WAITING• TERMINATED

Page 5: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

Старт потока через overridepublic void runOverridenThread() { Thread thread = new Thread() { @Override public void run() { // do something } }; thread.start();}

Page 6: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

Старт потока с Runnablepublic void runRunnableInThread() { Thread thread = new Thread(new Runnable() { @Override public void run() { // do something } }); thread.start();}

Page 7: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

Прерывание потокаpublic void interruptThread() throws Exception { Thread thread = new Thread(new Runnable() { @Override public void run() { while (!Thread.interrupted()) { // Do something useful } // Thread interrupted } }); thread.start(); Thread.sleep(1); thread.interrupt(); }

Page 8: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

Прерывание блокирующего вызоваpublic void interruptThread() throws Exception { Thread thread = new Thread(new Runnable() { @Override public void run() { while (!Thread.interrupted()) { // Do something useful try { Thread.sleep(1000); // blocking call } catch (InterruptedException e) { // Thread interrupted } } // Thread interrupted } }); thread.start(); Thread.sleep(1); thread.interrupt(); }

Page 9: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

Работа с памятью

Page 10: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

synchronized• Критическая секция• Допускается повторное вхождение (reentrant)• Синхронизироваться можно по любому объекту

• Необходимо минимизировать размер критических секций• По возможности, дробить критические секции на части• Можно использовать альтернативные блокировки

Page 11: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

synchronizedpublic static synchronized void sMethod() { // тело метода }

public static void sMethodDescribed () { synchronized (SynchronizedExample.class) { // тело метода }}

public synchronized void iMethod() { // тело метода }

public void iMethodDescribed() { synchronized (this) { // тело метода }}

private final Object lock = new Object(); public void anotherObject () { synchronized (lock) { // тело метода }}

Page 12: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

volatile• Форсирует работу с памятью в обход кешей• Гарантирует атомарное чтение и запись для double и long• Не гарантирует атомарный инкремент

private volatile long value;

Page 13: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

Atomic*• Базируются на операции compareAndSet(previous, next)• Это отдельная инструкция байт-кода JVM• Гарантирует атомарность чтения, записи и инкремента

• java.util.concurrent.atomic.*:• AtomicInteger• AtomicLong• AtomicBoolean• AtomicReference<T>• AtomicIntegerArray• AtomicLongArray

Page 14: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

Atomic incrementAndGet()public class AtomicInteger extends Number { private volatile int value;

private native boolean compareAndSet(int current, int next); public final int incrementAndGet () { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) { return next; } } } }

Page 15: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

Atomic getAndIncrement()public class AtomicInteger extends Number { private volatile int value;

private native boolean compareAndSet(int current, int next); public final int getAndIncrement() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) { return current; } } } }

Page 16: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

Immutable• Неизменяемые объекты не нуждаются в синхронизации

состояния, а значит, потокобезопасны

• Все поля – final (либо не изменяются)• Все mutable параметры конструктора скопированы• Ссылки на внутренние mutable объекты не публикуются• Родительский класс также immutable• Нет утечки ссылки на this из конструктора

Page 17: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

Проблемы многопоточности

Page 18: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

Deadlockclass Account { public int money;}

class AccountManager { public void transfer(Account from, Account to, int amount) { assert amount > 0;

synchronized (from) { assert from.money >= amount; synchronized (to) { to.money += amount; from.money -= amount; } } } }

Page 19: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

Lock orderingclass Account { public int money; public final long id;}

class AccountManager { public void transfer(Account from, Account to, int amount) { assert amount > 0; assert from.number != to.number; Object first = from.number < to.number ? from : to; Object second = from.number < to.number ? to : from; synchronized (first) { synchronized (second) { to.money += amount; from.money -= amount; } } } }

Page 20: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

Livelock• Поток успешно получает блокировку, однако выполнить полезное

действие не может• Два потока конфликтуют, откатывают результаты своей работы и

пытаются через фиксированное время повторить попытку (например, делают sleep(1000)).• При следующей попытке они опять будут конфликтовать• Пример – задача про обедающих философов• Решение – случайная задержка

Page 21: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

Starvation• Бесконечные циклы – холостая утилизация CPU• sleep при взятой блокировке• Blocking IO при взятой блокировке• Неоптимальные приоритеты потоков в ОС

Page 22: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

Решение проблем• Не использовать многопоточность• Не разделять состояние между потоками• Разделять только immutable-состояние• Использовать lock-free алгоритмы• Использовать готовые примитивы синхронизации• Аккуратнее программировать синхронизацию

Page 23: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

Примитивы синхронизации

https://habrahabr.ru/company/luxoft/blog/157273/

Page 24: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

Lock (ReentrantLock)• lock()• unlock()• tryLock()• tryLock(long timeout)

Page 25: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

ReadWriteLock• readLock().lock()• readLock().unlock()• writeLock().lock()• writeLock().unlock()

http://www.java67.com/2012/08/5-thread-interview-questions-answers-in.html

Page 26: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

CountDownLatch• new CountDownLatch(int count)• await()• countDown()

http://www.topjavatutorial.com/java/countdownlatch-in-java/

Page 27: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

А также• Semaphore• CyclicBarrier• Exchanger• Phaser

Page 28: Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor

Concurrent-коллекции• Vector, Stack, Hashtable• Collections.synchronized*()• ConcurrentHashMap, ConcurrentSkipListMap• CopyOnWriteArrayList, CopyOnWriteArraySet• BlockingQueue – ArrayBQ, LinkedBQ• ConcurrentLinkedQueue