4
4
5
5
import java .util .*;
6
6
import java .util .concurrent .atomic .AtomicBoolean ;
7
+ import java .util .concurrent .locks .ReentrantReadWriteLock ;
7
8
8
9
public class Tst implements StringTree {
9
10
10
11
private TstNode root ;
11
12
13
+ /**
14
+ * To make this container thread-safe, we need to synchronize all public methods.
15
+ * Instead of using a generic reentrant lock through the synchronized keyword,
16
+ * we define a Read/Write lock, so if we have more reads than writes, we can hold the lock
17
+ * without blocking other reads. Only writes block all other operations.
18
+ */
19
+ private ReentrantReadWriteLock .ReadLock readLock ;
20
+ private ReentrantReadWriteLock .WriteLock writeLock ;
21
+
12
22
public Tst () {
13
23
root = null ;
24
+
25
+ ReentrantReadWriteLock lock = new ReentrantReadWriteLock ();
26
+ readLock = lock .readLock ();
27
+ writeLock = lock .writeLock ();
14
28
}
15
29
16
30
@ Override
17
31
public boolean add (String element ) {
18
32
if (element .isEmpty ()) {
19
33
throw new IllegalArgumentException ("Keys must be non-empty" );
20
34
}
21
- if (root == null ) {
22
- root = new TstNode (element );
23
- return true ;
24
- } else {
25
- return root .add (element ) != null ;
35
+ writeLock .lock ();
36
+ try {
37
+ if (root == null ) {
38
+ root = new TstNode (element );
39
+ return true ;
40
+ } else {
41
+ return root .add (element ) != null ;
42
+ }
43
+ } finally {
44
+ writeLock .unlock ();
26
45
}
27
46
}
28
47
29
48
@ Override
30
49
public boolean remove (String element ) {
31
- if (root == null ) {
32
- return false ;
33
- } else {
34
- return root .remove (element );
50
+ writeLock .lock ();
51
+ try {
52
+ if (root == null ) {
53
+ return false ;
54
+ } else {
55
+ return root .remove (element );
56
+ }
57
+ } finally {
58
+ writeLock .unlock ();
35
59
}
36
60
}
37
61
38
62
@ Override
39
63
public void clear () {
40
- // Let the garbage collector do all the hard work
41
- root = null ;
64
+ writeLock .lock ();
65
+ try {
66
+ // Let the garbage collector do all the hard work
67
+ root = null ;
68
+ } finally {
69
+ writeLock .unlock ();
70
+ }
42
71
}
43
72
44
73
@ Override
45
74
public Optional <String > search (String element ) {
46
- return root .search (element ) == null ? Optional .empty () : Optional .of (element );
75
+ writeLock .lock ();
76
+ try {
77
+ return root .search (element ) == null ? Optional .empty () : Optional .of (element );
78
+ } finally {
79
+ writeLock .unlock ();
80
+ }
47
81
}
48
82
49
83
@ Override
@@ -58,32 +92,62 @@ public Iterable<String> keysWithPrefix(String prefix) {
58
92
59
93
@ Override
60
94
public Iterable <String > keys () {
61
- return root == null ? new HashSet <>() : root .keys ();
95
+ readLock .lock ();
96
+ try {
97
+ return root == null ? new HashSet <>() : root .keys ();
98
+ } finally {
99
+ readLock .unlock ();
100
+ }
62
101
}
63
102
64
103
@ Override
65
104
public Optional <String > min () {
66
- return Optional .ofNullable (root ).map (TstNode ::min );
105
+ readLock .lock ();
106
+ try {
107
+ return Optional .ofNullable (root ).map (TstNode ::min );
108
+ } finally {
109
+ readLock .unlock ();
110
+ }
67
111
}
68
112
69
113
@ Override
70
114
public Optional <String > max () {
71
- return Optional .ofNullable (root ).map (TstNode ::max );
115
+ readLock .lock ();
116
+ try {
117
+ return Optional .ofNullable (root ).map (TstNode ::max );
118
+ } finally {
119
+ readLock .unlock ();
120
+ }
72
121
}
73
122
74
123
@ Override
75
124
public boolean isEmpty () {
76
- return root == null || root .size () == 0 ;
125
+ readLock .lock ();
126
+ try {
127
+ return root == null || root .size () == 0 ;
128
+ } finally {
129
+ readLock .unlock ();
130
+ }
77
131
}
78
132
79
133
@ Override
80
134
public int size () {
81
- return root == null ? 0 : root .size ();
135
+ readLock .lock ();
136
+ try {
137
+ return root == null ? 0 : root .size ();
138
+ } finally {
139
+ readLock .unlock ();
140
+ }
82
141
}
83
142
84
143
@ Override
85
144
public int height () {
86
- return root == null ? 0 : root .height ();
145
+ readLock .lock ();
146
+ try {
147
+ return root == null ? 0 : root .height ();
148
+ } finally {
149
+ readLock .unlock ();
150
+ }
87
151
}
88
152
89
153
private class TstNode {
0 commit comments