Skip to content

Commit eecb0f9

Browse files
committed
doc update
1 parent aac58f7 commit eecb0f9

File tree

1 file changed

+104
-1
lines changed

1 file changed

+104
-1
lines changed

README.md

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,107 @@ In this project we will show how to use Execute Around Method
99
(EAM) pattern to wrap critical sections and minimise the pain
1010
of working with the `ReadWriteLock` interface.
1111

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

Comments
 (0)