Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Java весна 2014 лекция 5

427 views

Published on

  • Be the first to comment

  • Be the first to like this

Java весна 2014 лекция 5

  1. 1. Углубленное программирование на Java
 Лекция 5 «Многопоточность» Виталий Чибриков
  2. 2. План лекции 2 1. Thread, Runnable= 2. Frontend и Account Service= 3. Concurrent Collections= 4. Message System
  3. 3. Processes and Threads 3 Процессы Приложение со своим набором run-time ресурсов и собственной памятью Взаимодействие через Inter Process Communication ресурсы Можно запускать на нескольких компьютерах Потоки «Живут» в одном процессе Старт приложения – создание main потока Используют общую память (heap) и другие ресурсы приложения Потоки могут порождать другие потоки и взаимодействовать с ними
  4. 4. Что такое поток? 4 Поток Объект, у класса которого есть методы start() и run() После вызова метода start() будет выполнен run() Метод run() будет выполнен в своем стеке
  5. 5. Threads 5 main T1.run() T2.run() T1.start() T2.start() t
  6. 6. Порядок не определен 6 main T1.run() T2.run() T1.start() T2.start() t
  7. 7. Роль операционной системы 7 Операционная система Создает потоки Переключает потоки Следит за мониторами
  8. 8. interface Runnable 8 Всего один метод – run() Runnable Поток это объект, реазизующий интерфейс Runnable public class HelloRunnable implements Runnable { G public void run() { System.out.println("Hello from a thread!"); } public static void main(String args[]) { (new Thread(new HelloRunnable())).start(); } }
  9. 9. class Thread 9 class MyThread extends Thread Thread содержит метод start() ― запуск нового потока сlass Thread реализует интерфейс Runnable public class HelloThread extends Thread { public void run() { System.out.println("Hello from a thread!"); } G public static void main(String args[]) { (new HelloThread()).start(); } }
  10. 10. Runnable Runnable vs Thread 10 Runnable класс нужно передавать в конструктор Thread объекта Можно наследовать класс отличный от Thread Thread Содержит методы управления потоком Thread thread = Thread.currentThread(); Текущий Thread object можно получить в любом месте кода
  11. 11. Доступ к объекту потока Текущий Thread object можно получить в любом месте кода long getId() String getName() int getPriority() void setPriority(int priority) static void sleep(long ms) void interrupt() static boolean interrupted() void join() 11 Thread thread = Thread.currentThread(); Некоторые методы
  12. 12. sleep and interrupt Если нужно остановить выполнение потока Thread.sleep(1000) – остановит выполнение потока на 1 секунду Если нужно прервать выполнение потока thread.interrupt() – пошлет прерывание потоку thread try { Thread.sleep(5000); } catch (InterruptedException e) { // We've been interrupted. return; } G for (int i = 0; i < inputs.length; i++) { heavyTask(inputs[i]); if (Thread.interrupted()) { // We've been interrupted. return; } } 12
  13. 13. Если надо остановить текущий поток до окончания другого потока join 13 Текущий поток ждет пока завершиться поток thread В текущем потоке вызываем thread.join(). public class HelloThread extends Thread { public void run() { System.out.println(“1. Hello from a thread!"); } public static void main(String args[]) { Thread thread = new HelloThread(); thread.start(); thread.join(); System.out.println(“2. Hello from the main!"); } }
  14. 14. Взаимодействие потоков У потоков общий Heap Можно передать в два потока ссылку на один объект Потоки смогут менять общий объект и взаимодействовать через него 14 Как осуществить взаимодействие между потоками?
  15. 15. Java memory model Memory model + volatile 15 volatile – не кэшировать, всегда считывать из общей памяти Описывает то, как потоки должны взаимодействовать через общую память Кэширование значений в многопроцессорных средах Изменение порядка операций для оптимизации Основные проблемы final – не изменять значение переменной synchronized – отметить участок кода доступный только одному треду Инструменты для решения
  16. 16. Synchronization Демонстрация работы кода ThreadInterference.example(); Возможные ошибки одновременного доступа Thread Interference – потеря результата Memory Consistency Errors – ошибочное состояние общей памяти 16
  17. 17. Synchronization public synchronized void increment() { ++i; } public void addName(String name) { synchronized(lockObject) { lastName = name; nameCount++; } nameList.add(name); } 17 Synchronized methods Synchronized statements
  18. 18. Lock object (mutex) public class TwoLocks { private long c1 = 0; private long c2 = 0; private Object lock1 = new Object(); //the first lock private Object lock2 = new Object(); //the second lock public void c1Up() { synchronized(lock1) { c1++; } } G public void c2Up() { synchronized(lock2) { c2++; } } } 18
  19. 19. Deadlock public void c1c2Up() { synchronized(lock1) { c1++; synchronized(lock2) { c2++; } } } public void c2c1Up() { synchronized(lock2) { c2++; synchronized(lock1) { c1++; } } } 19
  20. 20. Служба в отдельном потоке 20 private boolean needDoSomething; G public void run() { while(true){ if(needDoSomething){ doSomething(); } Thread.sleep(1000); } }
  21. 21. wait() and notify() wait(), notify() и notifyAll() ― методы класса Object object.wait() ― ждать в текущем потоке, пока не придет notify() object.notify() ― сигнал «продолжить» первому кто начал wait() object.notifyAll() ― сигнал «продолжить» всем кто начал wait() Демонстрация работы кода RandomRunExample.example(); 21
  22. 22. План лекции 22 1. Thread, Runnable= 2. Frontend и Account Service= 3. Concurrent Collections= 4. Message System
  23. 23. UserSession 23 UserSession содержит: Каждому, кто пришел на сервер - UserSession Каждой UserSession – sessionId (из HttpSession) String sessionId String userName Long userId На Frontend-е Map<String, UserSession> sessionIdToSession;
  24. 24. В одном потоке 24 Назначаем Id для пользовательской сесcии В методе handle() спрашиваем у AccountService userId по имени Создаем объект Accounter, который будет скрывать авторизацию Ждем пока AccountService прочитает эти данные из базы Создаем на основе сесcии страницу и отдаем ее браузеру Сохраняем в объекте сессии данные о пользователе Спрашиваем у пользователя имя Авторизация
  25. 25. Временная диаграмма Авторизация 25 browser server start on localhost:8080 http://localhost:8080/ generate sessionId first access enter your name submit name load userId Hello user!
  26. 26. Frontend и Account Service 26 Frontend создает пользовательскую сессиюG Frontend возвращает страницу созданную на основе сесcии в браузерG Frontend запрашивает у Account Service данные по авторизацииG Когда данные приходят, Frontend меняет состояние сессии Разведем работу с пользователем и AccountService по разным потокамG Frontend ― поток который работает с пользователямиG AccountService ― поток который работает с авторизацией
  27. 27. Состояния 27 Ответ 2: sessionId + «Ждите авторизации» Запрос 0: Первый запрос страницы. Запрос 2: sessionId Запрос 3: sessionId Ответ 3: sessionId + «Ваше имя» + userName + « ваш Id: » + userId Ответ 0: sessionId + «Введите имя» Запрос 1: sessionId + Имя Ответ 1: sessionId + «Ждите авторизации» Запрос на AccountServer Ответ не пришел Ответ пришел
  28. 28. Frontend и Account Service Решение в 2 потока 28 frontend account service get Id from Storage get Id by name return Id for name Hello user! submit name wait for auth check state wait for auth check state
  29. 29. План лекции 29 1. Thread, Runnable= 2. Frontend и Account Service= 3. Concurrent Collections= 4. Message System
  30. 30. Atomic 30 java.util.concurrent.atomic AtomicBoolean AtomicInteger AtomicLong Реализованы без использования synchronized public final int incrementAndGet() { while (true) { int current = get(); //get() возвращает текущее значение (volatile) int next = current + 1; if (compareAndSet(current, next)) return next; } } public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } optimistic locking
  31. 31. Synchronized vs. Concurrent 31 Concurrent ― предназначена для работы с несколькими потоками,
 но не синхронная (без использования synchronized)G ConcurrentHashMap ― concurrent java.util.Hashtable ― synchronized synchronized ― гарантия, что только один поток работает с элементом Concurrent ― разрешено одновременное чтение и безопасная запись
  32. 32. Concurrent Collections 32 CopyOnWriteArrayListG G копирование при вставке в ArrayList CopyOnWriteArraySetG G Set интерфейс над CopyOnWriteArrayList ConcurrentHashMapG G thread safe HashMap ConcurrentSkipListMapGG ключи уникальны и отсортированы ConcurrentSkipListSetG G set на базе ConcurrentSkipListMap Контейнеры безопасные 
 для многопоточного доступа
  33. 33. Очереди безопасные 
 для многопоточного доступа Concurrent Queues 33 BlockingQueueGG G G очередь с ограничениме размера ConcurrentLinkedQueueG G G thread safe очередь LinkedBlockingQueue ArrayBlockingQueue BlockingDequeG G G G двухсторонняя «очередь» ArrayBlockingDeque
  34. 34. План лекции 34 1. Thread, Runnable= 2. Frontend и Account Service= 3. Concurrent Collections= 4. Message System
  35. 35. Thread-local объекты Основная идея Обмен сообщениями 35 Один поток кладет сообщение в коллекцию Второй поток достает сообщение и исполняет его Thread-Safe коллекции Безопасная работа с элементами коллекции Оптимальная работа Объекты на которые есть ссылки только из одного потока
  36. 36. MessageSystem ― 
 объект для обмена данными Message System 36 Одна система сообщений на процесс Единственный объект доступный из нескольких потоков По одной очереди сообщений на поток Каждый поток берет свою очередь из потока и выполняет сообщения Каждый поток имеет свой адрес Из любого места потока можно положить сообщение в очередь по адресу
  37. 37. Обмен сообщениями 37 Frontend Account G Service Account G Queue Frontend G Queue MsgToAccountService MsgToFrontend MessageSystem
  38. 38. Address и Abonent 38 public class Address { static private AtomicInteger abonentIdCreator = new AtomicInteger(); final private int abonentId; G public Address(){ this.abonentId = abonentIdCreator.incrementAndGet(); } G public int hashCode() { return abonentId; } } public interface Abonent { Address getAddress(); }
  39. 39. Message 39 public abstract class Msg { final private Address from; final private Address to; G public Msg(Address from, Address to){ this.from = from; this.to = to; } G protected Address getFrom(){ return from; } G protected Address getTo(){ return to; } G public abstract void exec(Abonent abonent); }
  40. 40. Message to Account Service 40 public abstract class MsgToAS extends Msg{ G public MsgToAS(Address from, Address to) { super(from, to); } G void exec(Abonent abonent) { if(abonent instanceof AccountService){ exec((AccountService) abonent); } } G abstract void exec(AccountService accountService); }
  41. 41. Message to Account Service 41 public class MsgGetUserId extends MsgToAS { private String name; private String sessionId; public MsgGetUserId(Address from, Address to, String name, String sessionId) { super(from, to); this.name= name; this.sessionId = sessionId; } G void exec(AccountService accountService) { Long id = accountService.getUserId(name); Msg back = new MsgUpdateUserId(getTo(), getFrom(), sessionId, id); accountService.getMessageSystem(). sendMessage(back); } }
  42. 42. Иерархия сообщений 42 Msg MsgToAS MsgToFrontend MsgUpdateUserIdMsgGetUserId - Address from - Address to - String name - Integer sessionId - Integer sessionId - Integer userId
  43. 43. Message System 43 private Map<Address, ConcurrentLinkedQueue<Msg>> messages = new HashMap<Address, ConcurrentLinkedQueue<Msg>>(); G G public void sendMessage(Msg message){ Queue<Msg> messageQueue = messages.get(message.getTo()); messageQueue.add(message); } G public void execForAbonent(Abonent abonent) { Queue<Msg> messageQueue = messages.get(abonent.getAddress()); while(!messageQueue.isEmpty()){ Msg message = messageQueue.poll(); message.exec(abonent); } }
  44. 44. MessageSystem ничего не знает о Frontend и AccountService Все что нужно MessageSystem это Address, Abonent и Msg Можно добавлять дополнительные сервисы Абстракция 44
  45. 45. Address Service 45 Часть Message System которая знает адреса абонентов Может вернуть адрес Account сервиса и Frontend Производит балансировку, если сервисов несколько
  46. 46. Address Service 46 public class AddressService { private Address accountService; G public Address getAccountService() { return accountService; } G public void setAccountService(Address accountService) { this.accountService = accountService; } } AddressService можно хранить в MessageSystemG G Address аккаунт сервера для пользователя можно хранить в UserSession
  47. 47. Обмен сообщениями 47 frontend account service get Id from Storage MsgGetUserId MsgUpdateUserId Hello user! submit name wait for auth check state wait for auth check state
  48. 48. Метод run() 48 public void run() { while (true) { messageSystem.execForAbonent(this); Thread.sleep(TICK_TIME); } }
  49. 49. Демонстрация кода 49 Переключаемся на код и смотрим как он работает
  50. 50. Спасибо за внимание Виталий Чибриков chibrikov@corp.mail.ru

×