Java осень 2013 лекция 3

396 views

Published on

Published in: Education
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
396
On SlideShare
0
From Embeds
0
Number of Embeds
58
Actions
Shares
0
Downloads
5
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Java осень 2013 лекция 3

  1. 1. Углубленное программирование на Java Лекция 3 «Message System» Виталий Чибриков
  2. 2. План лекции 1. Frontend и Account Service 2. Concurrent Collections 3. Message System 2
  3. 3. UserSession Каждому, кто пришел на сервер - UserSession Каждой UserSession – sessionId (из HttpSession) UserSession содержит: String sessionId String userName Long userId На Frontend-е Map<String, UserSession> sessionIdToSession; 3
  4. 4. В одном потоке Авторизация Назначаем Id для пользовательской сесcии Спрашиваем у пользователя имя Создаем объект Accounter, который будет скрывать авторизацию В методе handle() спрашиваем у Accounter userId по имени Ждем пока Accounter прочитает эти данные из файла или базы Сохраняем в объекте сессии данные о пользователе Создаем на основе сесcии страницу и отдаем ее браузеру 4
  5. 5. Авторизация Временная диаграмма 5
  6. 6. Frontend и Account Service Разведем работу с пользователем и Accounter по разным потокам Frontend ― поток который работает с пользователями Account Service ― поток который работает с авторизацией Frontend создает пользовательскую сессию Frontend возвращает страницу созданную на основе сесcии в браузер Frontend запрашивает у Account Service данные по авторизации Когда данные приходят, Frontend меняет состояние сессии 6
  7. 7. Состояния Запрос 0: Первый запрос страницы. Ответ 0: sessionId + «Введите имя» Запрос 1: sessionId + Имя Запрос на AccountServer Ответ 1: sessionId + «Ждите авторизации» Запрос 2: sessionId Ответ не пришел Ответ 2: sessionId + «Ждите авторизации» Запрос 3: sessionId Ответ пришел Ответ 3: sessionId + «Ваше имя» + userName + « ваш Id: » + userId 7
  8. 8. Решение в 2 потока Frontend и Account Service 8
  9. 9. План лекции 1. Frontend и Account Service 2. Concurrent Collections 3. Message System 9
  10. 10. Atomic java.util.concurrent.atomic AtomicBoolean AtomicInteger Реализованы без использования synchronized optimistic locking AtomicLong 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); } 10
  11. 11. Synchronized vs. Concurrent Concurrent ― предназначена для работы с несколькими потоками, но не синхронная (без использования synchronized) ConcurrentHashMap ― concurrent java.util.Hashtable ― synchronized synchronized ― гарантия, что только один поток работает с элементом Concurrent ― разрешено одновременное чтение и безопасная запись 11
  12. 12. Concurrent Collections Контейнеры безопасные для многопоточного доступа CopyOnWriteArrayList копирование при вставке в ArrayList CopyOnWriteArraySet Set интерфейс над CopyOnWriteArrayList ConcurrentHashMap thread safe HashMap ConcurrentSkipListMap ключи уникальны и отсортированы ConcurrentSkipListSet set на базе ConcurrentSkipListMap 12
  13. 13. Concurrent Queues Очереди безопасные для многопоточного доступа ConcurrentLinkedQueue thread safe очередь BlockingQueue ArrayBlockingQueue очередь с ограничениме размера LinkedBlockingQueue BlockingDeque ArrayBlockingDeque двухсторонняя «очередь» 13
  14. 14. План лекции 1. Frontend и Account Service 2. Concurrent Collections 3. Message System 14
  15. 15. Обмен сообщениями Основная идея Один поток кладет сообщение в коллекцию Второй поток достает сообщение и исполняет его Thread-Safe коллекции Безопасная работа с элементами коллекции Оптимальная работа Thread-local объекты Объекты на которые есть ссылки только из одного потока 15
  16. 16. Message System MessageSystem ― объект для обмена данными Одна система сообщений на процесс Единственный объект доступный из нескольких потоков По одной очереди сообщений на поток Каждый поток берет свою очередь из потока и выполняет сообщения Каждый поток имеет свой адрес Из любого места потока можно положить сообщение в очередь по адресу 16
  17. 17. Обмен сообщениями MsgToAccountService Frontend Frontend Queue MsgToFrontend Account Queue Account Service MessageSystem 17
  18. 18. Address и Abonent public class Address { static private AtomicInteger abonentIdCreator = new AtomicInteger(); final private int abonentId; public Address(){ this.abonentId = abonentIdCreator.incrementAndGet(); } public int hashCode() { return abonentId; } } public interface Abonent { Address getAddress(); } 18
  19. 19. Message public abstract class Msg { final private Address from; final private Address to; public Msg(Address from, Address to){ this.from = from; this.to = to; } protected Address getFrom(){ return from; } protected Address getTo(){ return to; } public abstract void exec(Abonent abonent); } 19
  20. 20. Message to Account Service public abstract class MsgToAS extends Msg{ public MsgToAS(Address from, Address to) { super(from, to); } void exec(Abonent abonent) { if(abonent instanceof AccountService){ exec((AccountService) abonent); } } abstract void exec(AccountService accountService); } 20
  21. 21. Message to Account Service 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; } void exec(AccountService accountService) { Long id = accountService.getUserId(name); Msg back = new MsgUpdateUserId(getTo(), getFrom(), sessionId, id); accountService.getMessageSystem(). sendMessage(back); } } 21
  22. 22. Иерархия сообщений Msg - Address from - Address to MsgToAS MsgToFrontend MsgGetUserId MsgUpdateUserId - String name - Integer sessionId - Integer sessionId - Integer userId 22
  23. 23. Message System private Map<Address, ConcurrentLinkedQueue<Msg>> messages = new HashMap<Address, ConcurrentLinkedQueue<Msg>>(); public void sendMessage(Msg message){ Queue<Msg> messageQueue = messages.get(message.getTo()); messageQueue.add(message); } public void execForAbonent(Abonent abonent) { Queue<Msg> messageQueue = messages.get(abonent.getAddress()); while(!messageQueue.isEmpty()){ Msg message = messageQueue.poll(); message.exec(abonent); } } 23
  24. 24. Абстракция MessageSystem ничего не знает о Frontend и AccountService Все что нужно MessageSystem это Address, Abonent и Msg Можно добавлять дополнительные сервисы 24
  25. 25. Address Service Часть Message System которая знает адреса абонентов Может вернуть адрес Account сервиса и Frontend Производит балансировку, если сервисов несколько 25
  26. 26. Address Service public class AddressService { private Address accountService; public Address getAccountService() { return accountService; } public void setAccountService(Address accountService) { this.accountService = accountService; } } AddressService можно хранить в MessageSystem Address аккаунт сервера для пользователя можно хранить в UserSession 26
  27. 27. Обмен сообщениями 27
  28. 28. Метод run() public void run() { while (true) { messageSystem.execForAbonent(this); Thread.sleep(TICK_TIME); } } 28
  29. 29. Демонстрация кода Переключаемся на код и смотрим как он работает 29
  30. 30. Спасибо за внимание Виталий Чибриков chibrikov@corp.mail.ru

×