-
Notifications
You must be signed in to change notification settings - Fork 90
/
ch27.html
591 lines (386 loc) · 37.4 KB
/
ch27.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Study guide for the Oracle Certified Professional, Java SE 8 Programmer Exam ">
<title>Java 8 Programmer II Study Guide: Exam 1Z0-809</title>
<link href="css/code.css" rel="stylesheet" type="text/css" />
<link href="css/style.css" rel="stylesheet" type="text/css" />
<link href="https://netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<script src="js/common-sections.js"></script>
</head>
<body>
<div class="nav"></div>
<div class="header">
<div class="title-container">
<div class="chapter-title">
<h1><i class="chapter">Chapter TWENTY-SEVEN</i><br />
Concurrency</h1>
<p><br /></p>
<h3 style="text-align: center;"><i>Exam Objectives</i></h3>
<p style="text-align: center;"><i>Use synchronized keyword and java.util.concurrent.atomic package to control the order of thread execution.<br /></i><i>Use java.util.concurrent collections and classes including CyclicBarrier and CopyOnWriteArrayList.</i></p>
</div>
</div>
</div>
<div class="container">
<div class="column">
<h2>Synchronization</h2>
<p>In the last chapter, we reviewed some problems that can happen in a concurrent environment and briefly talked about locking.</p>
<p>For example, one solution to avoid a race condition is to ensure that only one thread at a time can access the code that causes the problem; a process known as <i>synchronizing</i> that block of code.</p>
<p>Synchronization works with locks. Every object comes with a built-in lock and since there is only lock per object, only one thread can hold that lock at any time. The other threads cannot take the lock until the first thread releases it. Meanwhile, they are blocked.</p>
<p>You define a lock by using the <code>synchronized</code> keyword on either a block or a method. That lock is acquired when a thread enters an unoccupied synchronized block or method.</p>
<p>In a synchronized block, you use the <code>synchronized</code> keyword followed by either a reference variable:</p>
<p><code class="java hljs">Object o = <span class="hljs-keyword">new</span> Object();<br />
<span class="hljs-keyword"><br />
synchronized</span> (o) { <span class="hljs-comment">// Get the lock of Object o</span><br />
<span class="hljs-comment"> // Code guarded by the lock</span><br />
}</code></p>
<p>Or the <code>this</code> keyword:</p>
<p><code class="java hljs"><span class="hljs-comment">// Get the lock of the object this code belongs to</span><br />
<span class="hljs-keyword">synchronized</span> (<span class="hljs-keyword">this</span>) {<br />
<span class="hljs-comment"> // Code guarded by the lock</span><br />
}</code></p>
<p>The lock is released when the block ends.</p>
<p>You can also synchronize an entire method:</p>
<p><code class="java hljs"><span class="hljs-function"><span class="hljs-keyword">public</span> synchronize <span class="hljs-keyword">void</span> <span class="hljs-title">method</span><span class="hljs-params">()</span></span> {<br />
<span class="hljs-comment"> // Code guarded by the lock</span><br />
}</code></p>
<p>In this case, the lock belongs to the object on which the method is declared and is released when the method ends.</p>
<p>Notice that synchronizing a method is equivalent to this:</p>
<p><code class="java hljs"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">method</span><span class="hljs-params">()</span></span> {<br />
<span class="hljs-keyword"> synchronized</span> (<span class="hljs-keyword">this</span>) {<br />
<span class="hljs-comment"> // Code guarded by the lock</span><br />
}<br />
}</code></p>
<p>Static code can also be synchronized but instead of using <code>this</code> to acquire the lock of an instance of the class, it is acquired on the single class object that every instance of the class has associated:</p>
<p><code class="java hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyClass</span></span> {<br />
<span class="hljs-function"><span class="hljs-keyword"> synchronized</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">method</span><span class="hljs-params">()</span></span> {<br />
<span class="hljs-comment"> /** .. */</span><br />
}<br />
}</code></p>
<p>Is equivalent to:</p>
<p><code class="java hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyClass</span></span> {<br />
<span class="hljs-function"><span class="hljs-keyword"> static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">method</span><span class="hljs-params">()</span></span> {<br />
<span class="hljs-keyword"> synchronized</span> (MyClass.class) {<br />
<span class="hljs-comment"> /** ... */</span><br />
}<br />
}<br />
}</code></p>
<p>Now, for example, if we execute the following code:</p>
<p><code class="java hljs"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Test</span></span> {<br />
<span class="hljs-keyword"> static</span> <span class="hljs-keyword">int</span> n = <span class="hljs-number">0</span>;<br />
<span class="hljs-function"><span class="hljs-keyword"> static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">add</span><span class="hljs-params">()</span></span> {<br />
n++;<br />
System.out.println(n);<br />
}<br />
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span></span> {<br />
ExecutorService service = Executors.newFixedThreadPool(<span class="hljs-number">4</span>);<br />
Runnable r = () -> add();<br />
<span class="hljs-keyword"> for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">4</span>; i++) {<br />
service.execute(r);<br />
}<br />
service.shutdown();<br />
}<br />
}</code></p>
<p>By looking at one possible output, we can see that we have a race condition problem because four threads are executing the same code:</p>
<p><code class="hljs">2<br />
2<br />
3<br />
4</code></p>
<p>But when we synchronize the <code>add()</code> method to ensure only one thread can access it, the problem goes away:</p>
<p><code class="hljs">1<br />
2<br />
3<br />
4</code></p>
<h2>Atomic Classes</h2>
<p>The <code>java.concurrent.atomic</code> package contains classes to perform atomic operations, which are performed in a single step without the intervention of more than thread.</p>
<p>We have for example:</p>
<p><code class="java">AtomicBoolean</code>, <code>AtomicInteger</code>, <code>AtomicLong</code>, and <code>AtomicReference<V></code><br /> To update a value of the corresponding type (or object reference) atomically.</p>
<p><code class="java">AtomicIntegerArray</code>, <code>AtomicLongArray</code>, and <code>AtomicReferenceArray<E></code><br /> To update the elements of the corresponding array type (or object reference) atomically.</p>
<p>Each class has methods that perform operations like increments or updates in an atomic way. Take for example the <code>AtomicInteger</code> class (the other classes have similar methods):</p>
<p><code class="java">int addAndGet(int delta)</code><br /> Atomically adds the given value to the current value.</p>
<p><code class="java">boolean compareAndSet(int expect, int update</code>)<br /> Atomically sets the value to the given updated value if the current value equals the expected value.</p>
<p><code class="java">int decrementAndGet()</code><br /> Atomically decrements by one the current value.</p>
<p><code class="java">int get()</code><br /> Gets the current value.</p>
<p><code class="java">int getAndAdd(int delta)</code><br /> Atomically adds the given value to the current value.</p>
<p><code class="java">int getAndDecrement()</code><br /> Atomically decrements by one the current value.</p>
<p><code class="java">int getAndIncrement()</code><br /> Atomically increments by one the current value.</p>
<p><code class="java">int getAndSet(int newValue)</code><br /> Atomically sets to the given value and returns the old value.</p>
<p><code>int incrementAndGet()</code><br /> Atomically increments by one the current value.</p>
<p><code class="java">void set(int newValue)</code><br /> Sets to the given value.</p>
<p>The example about incrementing a variable we reviewed before can be rewritten as:</p>
<p><code class="java hljs"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Test</span></span> {<br />
<span class="hljs-keyword"> static</span> AtomicInteger n = <span class="hljs-keyword">new</span> AtomicInteger(<span class="hljs-number">0</span>);<br />
<span class="hljs-function"><span class="hljs-keyword"> static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">add</span><span class="hljs-params">()</span></span> {<br />
System.out.println(n.incrementAndGet());<br />
}<br />
<span class="hljs-function"><span class="hljs-keyword"> public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span></span> {<br />
...<br />
}<br />
}</code></p>
<p>When we execute this, we'll get all the numbers but not in order, because atomic classes only ensure data consistency:</p>
<p><code class="hljs">1<br />
4<br />
2<br />
3</code></p>
<h2>Concurrent Collections</h2>
<p>The <code>java.util.concurrent</code> package provides some thread-safe classes equivalent to the collection classes of <code>java.util</code>.</p>
<p>This way, instead of explicitly synchronizing an operation like this:</p>
<p><code class="java hljs">Map<String, Integer> map = <span class="hljs-keyword">new</span> HashMap<>();<br />
...<br />
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">putIfNew</span><span class="hljs-params">(String key, Integer val)</span></span> {<br />
<span class="hljs-keyword"> if</span>(map.get(key) == <span class="hljs-keyword">null</span>) {<br />
map.put(key, val);<br />
}<br />
}</code></p>
<p>You can use a <code>ConcurrentHashMap</code> like this:</p>
<p><code class="java hljs">Map<String, Integer> map = <span class="hljs-keyword">new</span> ConcurrentHashMap<>();<br />
...<br />
map.putIfAbsent(key, val);</code></p>
<p>So when working in concurrent environments, if you're to modify collections, it's better to use the collections of <code>java.util.concurrent</code> (besides, they often perform better than plain synchronization).</p>
<p>In fact, if you only need plain <code>get()</code> and <code>put()</code> methods (when working with a map, for example) you only have to change the implementation:</p>
<p><code class="java hljs"><span class="hljs-comment">//Map<String, Integer> map = new HashMap<>();</span><br />
Map<String, Integer> map = <span class="hljs-keyword">new</span> ConcurrentHashMap<>();<br />
map.put(<span class="hljs-string">"one"</span>, <span class="hljs-number">1</span>);<br />
Integer val = map.get(<span class="hljs-string">"one"</span>);</code></p>
<p>Java provides a lot of concurrent collections, but we can classify them by the interface they implement:</p>
<ul>
<li><code>BlockingQueue</code> (for queues)</li>
<li><code>BlockingDeque</code> (for deques)</li>
<li><code>ConcurrentMap</code> (for maps)</li>
<li><code>ConcurrentNavigableMap</code> (for navigable maps like <code>TreeMap</code>)</li>
</ul>
<p>Since these interfaces extends from the <code>java.util</code> collection interfaces, they inherit the methods we already know (and behave like one of them) so here you'll only find the added methods that support concurrency. And for lists, you can use the class <code>CopyOnWriteArrayList</code>.</p>
<p><b>BlockingQueue</b><br /> It represents a thread-safe queue that waits (with an optional timeout) for an element to be inserted if the queue is empty or for an element to be removed if the queue is full:</p>
<table border="1" width="100%">
<tr>
<td></td>
<td><b>Blocks</b></td>
<td><b>Times Out</b></td>
</tr>
<tr>
<td><b>Insert</b></td>
<td><code>void put(E e)</code></td>
<td><code>boolean offer(E e, long timeout, TimeUnit unit)</code></td>
</tr>
<tr>
<td><b>Remove</b></td>
<td><code>E take()</code></td>
<td><code>E poll(long timeout, TimeUnit unit)</code></td>
</tr>
</table>
<p>After the waiting time elapses, <code>offer()</code> returns <code>false</code> and <code>poll()</code> returns <code>null</code>.</p>
<p>The main implementations of this interface are:</p>
<ul>
<li><code>ArrayBlockingQueue</code>. A bounded blocking queue backed by an array.<br /></li>
<li><code>DelayQueue</code>. An unbounded blocking queue of <code>Delayed</code> elements, in which an element can only be taken when its delay has expired.<br /></li>
<li><code>LinkedBlockingQueue</code>. An optionally-bounded blocking queue based on linked nodes.<br /></li>
<li><code>LinkedTransferQueue</code>. An unbounded <code>TransferQueue</code> based on linked nodes.<br /></li>
<li><code>PriorityBlockingQueue</code>. An unbounded blocking queue that uses the same ordering rules as class <code>PriorityQueue</code> and supplies blocking and retrieval operations.<br /></li>
<li><code>SynchronousQueue</code>. A blocking queue in which each insert operation must wait for a corresponding remove operation by another thread, and vice versa. You cannot peek at a synchronous queue because an element is only present when you try to remove it.<br /></li>
</ul>
<p><b>BlockingDeque</b><br /> It represents a thread-safe deque (a double-ended queue, a queue which you can insert and take elements from in both ends). It extends from <code>BlockingQueue</code> and <code>Deque</code>, and also waits (with an optional timeout, after which, it returns <code>false</code> or <code>null</code> too) for an element to be inserted if the deque is empty or for an element to be removed if the deque is full:</p>
<table border="1" width="100%">
<tr>
<td colspan="3" style="text-align:center"><b>First Element (head)</b></td>
</tr>
<tr>
<td></td>
<td><b>Blocks</b></td>
<td><b>Times Out</b></td>
</tr>
<tr>
<td><b>Insert</b></td>
<td><code>void putFirst(E e)</code></td>
<td><code>boolean offerFirst(E e, long timeout, TimeUnit unit)</code></td>
</tr>
<tr>
<td><b>Remove</b></td>
<td><code>E takeFirst()</code></td>
<td><code>E pollFirst(long timeout, TimeUnit unit)</code></td>
</tr>
<tr>
<td colspan="3" style="text-align:center"><b>Last Element (tail)</b></td>
</tr>
<tr>
<td></td>
<td><b>Blocks</b></td>
<td><b>Times Out</b></td>
</tr>
<tr>
<td><b>Insert</b></td>
<td><code>void putLast(E e)</code></td>
<td><code>boolean offerLast(E e, long timeout, TimeUnit unit)</code></td>
</tr>
<tr>
<td><b>Remove</b></td>
<td><code>E takeLast()</code></td>
<td><code>E pollLast(long timeout, TimeUnit unit)</code></td>
</tr>
</table>
<p><b>ConcurrentMap</b><br /> This interface represents a thread-safe map and it's implemented by the <code>ConcurrentHashMap</code> class.</p>
<p>Here are some of its most important methods:</p>
<p><code class="java">V compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)</code><br /> Atomically computes the value of a specified key with a <code>BiFunction</code></p>
<p><code class="java">V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)</code><br /> Atomically computes the value of a key only if it's not present in the map</p>
<p><code class="java">V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)</code><br /> Atomically computes the value of a key only if it's present in the map</p>
<p><code class="java">V getOrDefault(Object key, V defaultValue)</code><br /> Returns the value of the key or a default value if the key is not present</p>
<p><code class="java">V merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)</code><br /> If the specified key is not already associated with a (non-<code>null</code>) value, associates it with the given value. Otherwise, replaces the value with the results of the given remapping function, or removes if <code>null</code>. This is performed atomically.</p>
<p><code class="java">V putIfAbsent(K key, V value)</code><br /> If the key is not present in the map, it's put with the given value atomically</p>
<p><b>ConcurrentNavigableMap</b><br /> It represents a thread-safe <code>NavigableMap</code> (like <code>TreeMap</code>) and is implemented by the <code>ConcurrentSkipListMap</code> class, sorted according to the natural ordering of its keys, or by a <code>Comparator</code> provided in its constructor.</p>
<p>A <code>ConcurrentNavigableMap</code> also implements <code>Map</code> and <code>ConcurrentMap</code>, so it has methods like <code>computeIfAbsent()</code>, <code>getOrDefault()</code>, etc.</p>
<p><b>CopyOnWriteArrayList</b><br /> It represents a thread-safe <code>List</code>, similar to an <code>ArrayList</code>, but when it's modified (with methods like <code>add()</code> or <code>set()</code>), a new copy of the underlying array is created (hence the name).</p>
<p>When iterating an <code>ArrayList</code>, methods like <code>remove()</code>, <code>add()</code> or <code>set()</code> can throw a <code>java.util.ConcurrentModificationException</code>. With a <code>CopyOnWriteArrayList</code>, this exception is not thrown because the iterator works with an unmodified copy of the list. But this also means that calling, for example, the <code>remove()</code> method on the <code>Iterator</code> is not supported (it throws an <code>UnsupportedOperationException</code>).</p>
<p>Consider this example, where the last element of the list is changed in every iteration but the original value is still printed inside the iterator:</p>
<p><code class="java hljs">List<Integer> list = <span class="hljs-keyword">new</span> CopyOnWriteArrayList<>();<br />
list.add(<span class="hljs-number">10</span>); list.add(<span class="hljs-number">20</span>); list.add(<span class="hljs-number">30</span>);<br />
Iterator<Integer> it = list.iterator();<br />
<span class="hljs-keyword">while</span>(it.hasNext()) {<br />
<span class="hljs-keyword"> int</span> i = it.next();<br />
System.out.print(i + <span class="hljs-string">" "</span>);<br />
<span class="hljs-comment">// No exception thrown<br /></span> list.set(list.size() -<span class="hljs-number">1</span>, i * <span class="hljs-number">10</span>);<br />
<span class="hljs-comment"> // it.remove(); throws an exception</span><br />
}<br />
System.out.println(list);</code></p>
<p>The output:</p>
<p><code class="hljs">10 20 30 [10, 20, 300]</code></p>
<p>With a <code>CopyOnWriteArrayList</code>, there is no lock on reads, so this operation is faster. For that reason, <code>CopyOnWriteArrayList</code> is most useful when you have few updates and inserts and many concurrent reads.</p>
<p>There are other classes like <code>ConcurrentSkipListSet</code>, which represents a thread-safe <code>NavigableSet</code> (like a <code>TreeSet</code>).</p>
<p>Or <code>CopyOnWriteArraySet</code>, which represents a thread-safe <code>Set</code> and internally uses a <code>CopyOnWriteArrayList</code> object for all of its operations (so these classes are very similar).</p>
<p>Besides all these classes, for each type of collection, the <code>Collections</code> class has methods like the following that take a normal collection and wrap it in a synchronized one:</p>
<p><code class="java hljs"><span class="hljs-keyword">static</span> <T> <span class="hljs-function">Collection<T> <span class="hljs-title">synchronizedCollection</span><span class="hljs-params">(Collection<T> c)</span><br />
<span class="hljs-keyword">static</span> <T> List<T> <span class="hljs-title">synchronizedList</span><span class="hljs-params">(List<T> list)</span><br />
<span class="hljs-keyword">static</span> <K,V> Map<K,V> <span class="hljs-title">synchronizedMap</span><span class="hljs-params">(Map<K,V> m)</span><br />
<span class="hljs-keyword">static</span> <T> Set<T> <span class="hljs-title">synchronizedSet</span><span class="hljs-params">(Set<T> s)</span></span></code></p>
<p>However, it's required to synchronize these collections manually when traversing them via an <code>Iterator</code> or <code>Stream</code>:</p>
<p><code class="java hljs">Collection c =<br />
Collections.synchronizedCollection(myCollection);<br />
...<br />
<span class="hljs-keyword">synchronized</span> (c) {<br />
Iterator i = c.iterator();<br />
...<br />
}</code></p>
<p>Also, they throw an exception if they are modified within an iteration.</p>
<p>Only use these methods if you have to work with an existing collection in a concurrent environment (otherwise, from the beginning, use a <code>java.util.concurrent</code> collection).</p>
<h2>CyclicBarrier</h2>
<p>The <code>synchronized</code> keyword helps us coordinate access to a shared resource by multiple threads.</p>
<p>But this is very low-level work. I mean, it takes a lot of effort to coordinate complex concurrent tasks. Luckily, Java provides high-level classes to more easily implement these kinds of synchronization tasks.</p>
<p>One of these classes is <code>CyclicBarrier</code>. It provides a synchronization point (a barrier point) where a thread may need to wait until all other threads also reach that point.</p>
<p>This class has two constructors:</p>
<p><code class="java">CyclicBarrier(int threads)</code><br /> Creates a <code>CyclicBarrier</code> with the specified number of threads waiting for it.</p>
<p><code class="java">CyclicBarrier(int parties, Runnable barrierAction)</code><br /> Creates a <code>CyclicBarrier</code> with the specified number of threads waiting upon it, and which will execute the given action when the barrier is reached.</p>
<p>The methods:</p>
<p><code class="java hljs"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">await</span><span class="hljs-params">()</span><br />
<span class="hljs-keyword"> throws</span> InterruptedException, BrokenBarrierException<br />
<span class="hljs-keyword">int</span> <span class="hljs-title">await</span><span class="hljs-params">(<span class="hljs-keyword">long</span> timeout, TimeUnit unit)</span><br />
<span class="hljs-keyword"> throws</span> InterruptedException,<br />
BrokenBarrierException,<br />
TimeoutException</span></code></p>
<p>Block a thread until all the other threads have called <code>await()</code> (reached the barrier), or optionally, until the specified waiting time elapses (when this happens, a <code>TimeoutException</code> is thrown).</p>
<p>These methods throw an <code>InterruptedException</code> if the current thread was interrupted while waiting and a <code>BrokenBarrierException</code> if another thread was interrupted or timed out, or the barrier was reset (with the <code>reset()</code> method), or the barrier action failed due to an exception.</p>
<p>Here's an example:</p>
<p><code class="java hljs"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CyclicBarrierExample</span></span> {<br />
<span class="hljs-function"><span class="hljs-keyword"> static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">checkStep</span><span class="hljs-params">(<br />
CyclicBarrier barrier, String step)</span></span> {<br />
<span class="hljs-comment"> // Do something to prepare the step</span><br />
System.out.println(step + <span class="hljs-string">" is ready"</span>);<br />
<span class="hljs-keyword"> try</span> {<br />
<span class="hljs-comment">// Wait the other threads<br /></span> barrier.await();<br />
} <span class="hljs-keyword">catch</span> (Exception e) { <span class="hljs-comment">/** ... */</span> }<br />
}<br />
<span class="hljs-function"><span class="hljs-keyword"> public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span></span> {<br />
String[] steps = {<span class="hljs-string">"Read the recipe"</span>,<br />
<span class="hljs-string"> "Gather the ingredients"</span>,<br />
<span class="hljs-string"> "Wash hands"</span>};<br />
System.out.println(<span class="hljs-string">"Preparing everything:"</span>);<br />
<br />
Runnable allSet = () -><br />
System.out.println( <span class="hljs-string">"Everything's ready. Let's begin."</span>);<br />
<br />
ExecutorService executor =<br />
Executors.newFixedThreadPool(steps.length);<br />
CyclicBarrier barrier =<br />
<span class="hljs-keyword"> new</span> CyclicBarrier(steps.length, allSet);<br />
<br />
<span class="hljs-keyword"> for</span>(String step : steps) {<br />
executor.submit(<br />
() -> checkStep(barrier, step)<br />
);<br />
}<br />
<br />
executor.shutdown();<br />
}<br />
}</code></p>
<p>The output:</p>
<p><code class="hljs">Preparing everything:<br />
Gather the ingredients is ready<br />
Read the recipe is ready<br />
Wash hands is ready<br />
Everything's ready. Let's begin.</code></p>
<p>We have three steps and one thread to process each one. The threads will print the given step and call the <code>await()</code> method. When the three threads have called that method, the <code>Runnable</code> represented by the <code>allSet</code> variable is executed (the one that prints the <code>"Everything's ready..."</code> message).</p>
<p>As you can see, the steps are not printed in order, but the program cannot proceed until all of them are executed.</p>
<p>Notice that the <code>CyclicBarrier</code> is created with the same number of threads. It has to be this way. Otherwise, the program will wait forever.</p>
<p>If the number of threads is less than the <code>CyclicBarrier</code> expects, it will wait forever for the missing threads.</p>
<p>To understand why the program will block when the number of threads is greater, you need to know that a <code>CyclicBarrier</code> can be reused and how that works.</p>
<p>When all the expected threads call <code>await()</code>, the number of waiting threads on the <code>CyclicBarrier</code> goes back to zero and it can be used again for a new set of threads. This way, if the <code>CyclicBarrier</code> expects three threads but there are four, a cycle of three will be completed and for the next, two will be missing, which will block the program.</p>
<h2>Key Points</h2>
<ul>
<li>Synchronization works with locks. Every object comes with a built-in lock and since there is only lock per object, only one thread can hold that lock at any time. You acquire a lock by using the <code>synchronized</code> keyword in either a block or a method.</li>
<li>Static code can also be synchronized but instead of using this to acquire the lock of an instance of the class, it is acquired on the class object that every class has associated.</li>
<li>The <code>java.util.concurrent.atomic</code> package contains classes (like <code>AtomicInteger</code>) to perform atomic operations, which are performed in a single step without the intervention of more than thread.</li>
<li><code>BlockingQueue</code> represents a thread-safe queue and <code>BlockingDeque</code> represents a thread-safe deque. Both wait (with an optional timeout) for an element to be inserted if the queue/deque is empty or for an element to be removed if the queue/deque is full.</li>
<li><code>ConcurrentMap</code> represents a thread-safe map and it's implemented by the <code>ConcurrentHashMap</code> class. <code>ConcurrentNavigableMap</code> represents a thread-safe <code>NavigableMap</code> (like <code>TreeMap</code>) and is implemented by the <code>ConcurrentSkipListMap</code> class.</li>
<li><code>CopyOnWriteArrayList</code> represents a thread-safe <code>List</code>, similar to an <code>ArrayList</code>, but when it's modified (with methods like <code>add()</code> or <code>set()</code>), a new copy of the underlying array is created (hence the name).</li>
<li><code>CyclicBarrier</code> that provides a synchronization point (a barrier point) where a thread may need to wait until all other threads reach that point.</li>
</ul>
<h2>Self Test</h2>
<p>1. Which of the following statements is true?<br /> A. <code>ConcurrentNavigableMap</code> has two implementations, <code>ConcurrentSkipListMap</code> and <code>ConcurrentSkipListSet</code><br /> B. The <code>remove()</code> method of <code>CopyOnWriteArrayList</code> creates a new copy of the underlying array on which this class is based.<br /> C. A <code>static</code> method can acquire the lock of an instance variable.<br /> D. Constructors can be synchronized.</p>
<p>2. Which of the following options will correctly increment a value inside a map in a thread-safe way?</p>
<p>A.</p>
<p><code class="java hljs">Map<String, Integer> map = <span class="hljs-keyword">new</span> ConcurrentHashMap<>();<br />
<span class="hljs-keyword">int</span> i = map.get(key);<br />
map.put(key, ++i);</code></p>
<p>B.</p>
<p><code class="java hljs">ConcurrentMap<String, Integer> map = <span class="hljs-keyword">new</span> ConcurrentHashMap<>();<br />
map.put(key, map.get(key)+<span class="hljs-number">1</span>);</code></p>
<p>C.</p>
<p><code class="java hljs">Map<String, Integer> map = <span class="hljs-keyword">new</span> HashMap<>();<br />
Map<String, Integer> map2 = Collections.synchronizedMap(map);<br />
<span class="hljs-keyword">int</span> i = map.get(key);<br />
map.put(key, ++i);</code></p>
<p>D.</p>
<p><code class="java hljs">Map<String, AtomicInteger> map = <span class="hljs-keyword">new</span> ConcurrentHashMap<>();<br />
map.get(key).incrementAndGet();</code></p>
<p>3. Given:</p>
<p><code class="java hljs"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Question_27_3</span></span> {<br />
<span class="hljs-function"><span class="hljs-keyword"> public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception</span> {<br />
BlockingDeque<Integer> deque =<br />
<span class="hljs-keyword"> new</span> LinkedBlockingDeque<>();<br />
deque.offerLast(<span class="hljs-number">10</span>, <span class="hljs-number">5</span>, TimeUnit.SECONDS);<br />
System.out.print(<br />
deque.pollLast(<span class="hljs-number">5</span>, TimeUnit.SECONDS)<br />
+ <span class="hljs-string">" "<br /></span> );<br />
System.out.print(<br />
deque.pollFirst(<span class="hljs-number">5</span>, TimeUnit.SECONDS));<br />
}<br />
}</code></p>
<p>What is the result?<br /> A. The program just prints <code>10</code><br /> B. The program prints <code>10</code> and hangs forever<br /> C. After 5 seconds, the program prints <code>10</code> and after another 5 seconds, it prints <code>null</code><br /> D. The program prints <code>10</code> and 5 seconds later, it prints <code>null</code></p>
<p>4. Under what circumstances can the <code>await()</code> method of <code>CyclicBarrier</code> throw an exception?<br /> A. If the thread goes to sleep<br /> B. When the last thread calls <code>await()</code><br /> C. If any thread is interrupted<br /> D. If the number of threads that call <code>await()</code> is different than the number of threads <code>CyclicBarrier</code> was created with.</p>
<div class="answers">
<a href="ch27a.html" target="_blank">Open answers page</a>
</div>
<div class="book-info"></div>
<div class="linkbox">
<div class="previous">
<a href="ch26.html">26. Thread Basics</a>
</div>
<div class="next">
<a href="ch28.html">28. Fork/Join Framework</a>
</div>
<div style="clear:both;"></div>
</div>
</div>
</div>
</body>
</html>