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

Preview:

Citation preview

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

на JavaЛекция 3

«Message System»

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

1. Frontend и Account Service

2. Concurrent Collections

3. Message System

План лекции

2

UserSession

3

UserSession содержит:

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

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

String sessionId

String userName

Long userId

На Frontend-е

Map<String, UserSession> sessionIdToSession;

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

4

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

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

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

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

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

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

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

Авторизация

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

Авторизация

5

Frontend и Account Service

6

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

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

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

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

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

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

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

Состояния

7

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

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

Запрос 2: sessionId

Запрос 3: sessionId

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

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

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

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

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

Ответ пришел

Frontend и Account Service

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

8

1. Frontend и Account Service

2. Concurrent Collections

3. Message System

План лекции

9

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

Synchronized vs. Concurrent

11

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

ConcurrentHashMap ― concurrent

java.util.Hashtable ― synchronized

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

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

Concurrent Collections

12

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

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

ConcurrentHashMap thread safe HashMap

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

ConcurrentSkipListSet set на базе ConcurrentSkipListMap

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

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

Concurrent Queues

13

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

ConcurrentLinkedQueue thread safe очередь

LinkedBlockingQueue

ArrayBlockingQueue

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

ArrayBlockingDeque

1. Frontend и Account Service

2. Concurrent Collections

3. Message System

План лекции

14

Thread-local объекты

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

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

15

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

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

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

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

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

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

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

Message System

16

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

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

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

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

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

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

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

17

FrontendAccount Service

Account Queue

Frontend Queue

MsgToAccountService MsgToFrontend

MessageSystem

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

}

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

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

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

}}

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

22

Msg

MsgToAS MsgToFrontend

MsgUpdateUserIdMsgGetUserId

- Address from

- Address to

- String name

- Integer sessionId

- Integer sessionId

- Integer userId

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

}}

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

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

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

Абстракция

24

Address Service

25

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

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

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

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

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

27

Метод run()

28

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

Thread.sleep(TICK_TIME);}

}

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

29

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

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

Виталий Чибриковchibrikov@corp.mail.ru