Transcript
Page 1: Java осень 2013 лекция 3

Углубленное программирование

на JavaЛекция 3

«Message System»

Виталий Чибриков

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

1. Frontend и Account Service

2. Concurrent Collections

3. Message System

План лекции

2

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

UserSession

3

UserSession содержит:

Каждому, кто пришел на сервер - UserSession

Каждой UserSession – sessionId (из HttpSession)

String sessionId

String userName

Long userId

На Frontend-е

Map<String, UserSession> sessionIdToSession;

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

В одном потоке

4

Назначаем Id для пользовательской сесcии

В методе handle() спрашиваем у Accounter userId по имени

Создаем объект Accounter, который будет скрывать авторизацию

Ждем пока Accounter прочитает эти данные из файла или базы

Создаем на основе сесcии страницу и отдаем ее браузеру

Сохраняем в объекте сессии данные о пользователе

Спрашиваем у пользователя имя

Авторизация

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

Временная диаграмма

Авторизация

5

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

Frontend и Account Service

6

Frontend создает пользовательскую сессию

Frontend возвращает страницу созданную на основе сесcии в браузер

Frontend запрашивает у Account Service данные по авторизации

Когда данные приходят, Frontend меняет состояние сессии

Разведем работу с пользователем и Accounter по разным потокам

Frontend ― поток который работает с пользователями

Account Service ― поток который работает с авторизацией

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

Состояния

7

Ответ 2: sessionId + «Ждите авторизации»

Запрос 0: Первый запрос страницы.

Запрос 2: sessionId

Запрос 3: sessionId

Ответ 3: sessionId + «Ваше имя» + userName + « ваш Id: » + userId

Ответ 0: sessionId + «Введите имя»

Запрос 1: sessionId + Имя

Ответ 1: sessionId + «Ждите авторизации»Запрос на AccountServer

Ответ не пришел

Ответ пришел

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

Frontend и Account Service

Решение в 2 потока

8

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

1. Frontend и Account Service

2. Concurrent Collections

3. Message System

План лекции

9

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

Atomic

10

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

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

Synchronized vs. Concurrent

11

Concurrent ― предназначена для работы с несколькими потоками,но не синхронная (без использования synchronized)

ConcurrentHashMap ― concurrent

java.util.Hashtable ― synchronized

synchronized ― гарантия, что только один поток работает с элементом

Concurrent ― разрешено одновременное чтение и безопасная запись

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

Concurrent Collections

12

CopyOnWriteArrayList копирование при вставке в ArrayList

CopyOnWriteArraySet Set интерфейс над CopyOnWriteArrayList

ConcurrentHashMap thread safe HashMap

ConcurrentSkipListMap ключи уникальны и отсортированы

ConcurrentSkipListSet set на базе ConcurrentSkipListMap

Контейнеры безопасные для многопоточного доступа

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

Очереди безопасные для многопоточного доступа

Concurrent Queues

13

BlockingQueue очередь с ограничениме размера

ConcurrentLinkedQueue thread safe очередь

LinkedBlockingQueue

ArrayBlockingQueue

BlockingDeque двухсторонняя «очередь»

ArrayBlockingDeque

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

1. Frontend и Account Service

2. Concurrent Collections

3. Message System

План лекции

14

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

Thread-local объекты

Основная идея

Обмен сообщениями

15

Один поток кладет сообщение в коллекцию

Второй поток достает сообщение и исполняет его

Thread-Safe коллекции

Безопасная работа с элементами коллекции

Оптимальная работа

Объекты на которые есть ссылки только из одного потока

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

MessageSystem ―объект для обмена данными

Message System

16

Одна система сообщений на процесс

Единственный объект доступный из нескольких потоков

По одной очереди сообщений на поток

Каждый поток берет свою очередь из потока и выполняет сообщения

Каждый поток имеет свой адрес

Из любого места потока можно положить сообщение в очередь по адресу

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

Обмен сообщениями

17

FrontendAccount Service

Account Queue

Frontend Queue

MsgToAccountService MsgToFrontend

MessageSystem

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

Address и Abonent

18

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();

}

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

Message

19

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);}

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

Message to Account Service

20

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);}

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

Message to Account Service

21

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);

}}

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

Иерархия сообщений

22

Msg

MsgToAS MsgToFrontend

MsgUpdateUserIdMsgGetUserId

- Address from

- Address to

- String name

- Integer sessionId

- Integer sessionId

- Integer userId

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

Message System

23

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);

}}

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

MessageSystem ничего не знает о Frontend и AccountService

Все что нужно MessageSystem это Address, Abonent и Msg

Можно добавлять дополнительные сервисы

Абстракция

24

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

Address Service

25

Часть Message System которая знает адреса абонентов

Может вернуть адрес Account сервиса и Frontend

Производит балансировку, если сервисов несколько

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

Address Service

26

public class AddressService {private Address accountService;

public Address getAccountService() {return accountService;

}

public void setAccountService(Address accountService) {this.accountService = accountService;

}}

AddressService можно хранить в MessageSystem

Address аккаунт сервера для пользователя можно хранить в UserSession

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

Обмен сообщениями

27

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

Метод run()

28

public void run() {while (true) {messageSystem.execForAbonent(this);

Thread.sleep(TICK_TIME);}

}

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

Демонстрация кода

29

Переключаемся на код и смотрим как он работает

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

Спасибо за внимание

Виталий Чибриков[email protected]