@@ -9,4 +9,107 @@ In this project we will show how to use Execute Around Method
9
9
(EAM) pattern to wrap critical sections and minimise the pain
10
10
of working with the ` ReadWriteLock ` interface.
11
11
12
- # project description
12
+ # project description
13
+ The main goal: simple implementation of transferring
14
+ money from user to user.
15
+
16
+ 1 . ` User ` class
17
+ ```
18
+ @Value
19
+ class User {
20
+ int id;
21
+ int balance;
22
+
23
+ User income(PositiveInt value) {
24
+ return new User(id, balance + value.amount);
25
+ }
26
+
27
+ User outcome(PositiveInt value) {
28
+ return new User(id, balance - value.amount);
29
+ }
30
+ }
31
+ ```
32
+ ```
33
+ class PositiveInt {
34
+ final int amount;
35
+
36
+ private PositiveInt(int amount) {
37
+ this.amount = amount;
38
+ }
39
+
40
+ static PositiveInt of(int amount) {
41
+ Preconditions.checkArgument(amount > 0);
42
+
43
+ return new PositiveInt(amount);
44
+ }
45
+ }
46
+ ```
47
+ 1. Immutable map of users:
48
+ ```
49
+ Map<Integer, User> userMap = Map.of(
50
+ 1, new User(1, 40),
51
+ 2, new User(2, 33)
52
+ );
53
+ ```
54
+ 1. We want to provide tread-safe read and writes on that map
55
+ * we will use `ReadWriteLock` interface
56
+ * we provide class that absorbs the pain of working
57
+ with that interface (locking/unlocking tiresome obligation)
58
+ ```
59
+ * we will supply action to execute in locked block
60
+ @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
61
+ @RequiredArgsConstructor
62
+ class LockExecutor {
63
+ ReadWriteLock lock;
64
+
65
+ <T> T write(Supplier<T> action) {
66
+ lock.writeLock().lock();
67
+ try {
68
+ return action.get();
69
+ } finally {
70
+ lock.writeLock().unlock();
71
+ }
72
+ }
73
+
74
+ <T> T read(Supplier<T> action) {
75
+ lock.readLock().lock();
76
+ try {
77
+ return action.get();
78
+ } finally {
79
+ lock.readLock().unlock();
80
+ }
81
+ }
82
+ }
83
+ ```
84
+ **Remark:** we choose `Supplier` as a parameter, because
85
+ it's often very handy to return a value from that methods.
86
+
87
+ # tests
88
+ 1. We want to transfer 15 credits from the first user, to the
89
+ second one
90
+ ```
91
+ ReadWriteLock lock = new ReentrantReadWriteLock();
92
+ LockExecutor executor = new LockExecutor(lock);
93
+
94
+ var transferred = executor.write(() -> {
95
+ var transfer = PositiveInt.of(15);
96
+ return Map.of(1, userMap.get(1).outcome(transfer),
97
+ 2, userMap.get(2).income(transfer));
98
+ });
99
+
100
+ assertThat(transferred.get(1).getBalance(), is(25));
101
+ assertThat(transferred.get(2).getBalance(), is(48));
102
+ ```
103
+ 1. We want to sum all balances from all users
104
+ ```
105
+ ReadWriteLock lock = new ReentrantReadWriteLock();
106
+ LockExecutor executor = new LockExecutor(lock);
107
+
108
+ var balanceAll = executor.read(() -> userMap.values()
109
+ .stream()
110
+ .map(User::getBalance)
111
+ .mapToInt(x -> x)
112
+ .sum());
113
+
114
+ assertThat(balanceAll, is(73));
115
+ ```
0 commit comments