Алгоритм PingPong очень прост
если моя очередь {
обновить чья очередь
пинг / понг -лог хит
уведомить другие темы
} еще {
ждать уведомления
}
Давайте рассмотрим пример и посмотрим, как это работает! Вот наш класс Player, который реализует Runnable и принимает доступ к общему ресурсу и сообщению
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
public class Player implements Runnable { PingPong myTable; Table where they play String myOpponent; public Player(String opponent, PingPong table) { myTable = table; myOpponent = opponent; } public void run() { while (myTable.hit(myOpponent)) ; }} |
Во-вторых, мы видим класс таблицы PingPong, у которого есть синхронизированный метод hit (), где выполняется проверка, если мой ход или нет. Если мой ход, войдите в пинг и обновите общую переменную для имени оппонента.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
public class PingPong { state variable identifying whose turn it is. private String whoseTurn = null; public synchronized boolean hit(String opponent) { String x = Thread.currentThread().getName(); if (x.compareTo(whoseTurn) == 0) { System.out.println('PING! (' + x + ')'); whoseTurn = opponent; notifyAll(); } else { try { wait(2500); } catch (InterruptedException e) { } } }} |
Далее мы начинаем игру и начинаем игроков!
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public class Game { public static void main(String args[]) { PingPong table = new PingPong(); Thread alice = new Thread(new Player('bob', table)); Thread bob = new Thread(new Player('alice', table)); alice.setName('alice'); bob.setName('bob'); alice.start(); alice starts playing bob.start(); bob starts playing try { Wait 5 seconds Thread.sleep(5000); } catch (InterruptedException e) { } table.hit('DONE'); cause the players to quit their threads. try { Thread.sleep(100); } catch (InterruptedException e) { } }} |
Вот и все, у нас запущена игра в пинг-понг. В этом случае мы увидели, как синхронизированный метод hit () позволяет только одному потоку обращаться к общему ресурсу — whichTurn.
Akka STM предоставляет две конструкции Refs и Agents. Refs (Transactional References) обеспечивают согласованный синхронный доступ к нескольким удостоверениям. Агенты предоставляют несогласованный асинхронный доступ к единому идентификатору.
Refs
В нашем случае, поскольку переменная состояния общего ресурса является единым идентификатором, использование Refs является излишним, но все же мы продолжим и увидим их использование.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public class PingPong { updates to Ref.View are synchronous Ref.View<String> whoseTurn; public PingPong(Ref.View<String> player) { whoseTurn = player; } public boolean hit(final String opponent) { final String x = Thread.currentThread().getName(); if (x.compareTo(whoseTurn.get()) == 0) { System.out.println('PING! (' + x + ')'); whoseTurn.set(opponent); } else { try { wait(2500); } catch (Exception e) { } }}} |
Ключ здесь следующие
- Синхронизированное ключевое слово отсутствует
- Определение переменной состояния как Ref
// обновления в Ref.View являются синхронными
Ref.View <string> whoTurn; - Звонки для обновления Ref согласованы и синхронны
whoTurn.set (противник) ;
Таким образом, когда мы используем Ref для хранения состояния, доступ к ссылкам автоматически синхронизируется в транзакции.
Агенты
Поскольку агенты предоставляют несогласованный асинхронный доступ, использование агентов для манипулирования состоянием будет означать, что нам нужно подождать, пока все обновления будут применены к агенту. Агенты предоставляют неблокирующий доступ для получения.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public class PingPong { Agent<String> whoseTurn; public PingPong(Agent<String> player) { whoseTurn = player; } public boolean hit(final String opponent) { final String x = Thread.currentThread().getName(); wait till all the messages are processed to make you get the correct value, as updated to Agents are async String result = whoseTurn.await(new Timeout(5, SECONDS)); if (x.compareTo(result) == 0) { System.out.println('PING! (' + x + ')'); whoseTurn.send(opponent); } else { try { wait(2500); } catch (Exception e) { } } return true; keep playing. }} |
Ключ здесь следующие
- Синхронизированное ключевое слово отсутствует
- Определение переменной состояния в качестве агента
// обновления в Ref.View являются синхронными
Агент <string> whoTurn; - Дождитесь обновления агента, поскольку обновления агента являются асинхронными
String result = whoTurn.await (новый тайм-аут (5, СЕКУНД)); - Звонки для обновления Ref согласованы и синхронны
whoTurn.send (противник) ;
Весь код, указанный в этом примере, доступен по адресу — https://github.com/write2munish/Akka-Essentials/tree/master/AkkaSTMExample/src/main/java/org/akka/essentials/stm/pingpong с
Пример 1 — для нормальной синхронизации на основе потоков
Пример 2 — Использование ссылок для синхронизации
Пример 3 — Использование Агентов для синхронизации
Справка: игра в пинг-понг с STM — ссылками и агентами от нашего партнера по JCG Муниша К Гупты в блоге Akka Essentials .
