Java Reference
In-Depth Information
pool-1-thread-2 wrote 12 to element 4.
Next write index: 5
pool-1-thread-2 wrote 13 to element 5.
Next write index: 6
Contents of SimpleArray:
[11, 2, 3, 0, 12, 13]
Fig. 23.7
|
Executing two
Runnable
s to add elements to a shared array. (
Caution:
The example
of Figs. 23.5-23.7 is
not
thread safe.) (Part 3 of 3.)
ExecutorService
Method
awaitTermination
Recall that
ExecutorService
method
shutdown
returns immediately. Thus any code that
appears
after
the call to
ExecutorService
method
shutdown
in line 23
will continue exe-
cuting as long as the
main
thread is still assigned to a processor
. We'd like to output the
Sim-
pleArray
object to show you the results
after
the threads complete their tasks. So, we need
the program to wait for the threads to complete before
main
outputs the
SimpleArray
ob-
ject's contents. Interface
ExecutorService
provides the
awaitTermination
method for
this purpose. This method returns control to its caller either when all tasks executing in
the
ExecutorService
complete or when the specified timeout elapses. If all tasks are com-
pleted before
awaitTermination
times out, this method returns
true
; otherwise it returns
false
. The two arguments to
awaitTermination
represent a timeout value and a unit of
measure specified with a constant from class
TimeUnit
(in this case,
TimeUnit.MINUTES
).
Method
awaitTermination
throws an
InterruptedException
if the calling thread is
interrupted while waiting for other threads to terminate. Because we catch this exception
in the application's
main
method, there's no need to re-interrupt the
main
thread as this
program will terminate as soon as
main
terminates.
In this example, if
both
tasks complete before
awaitTermination
times out, line 34
displays the
SimpleArray
object's contents. Otherwise, lines 37-38 display a message indi-
cating that the tasks did not finish executing before
awaitTermination
timed out.
Sample Program Output
Figure 23.7's output shows the problems (highlighted in the output) that can be caused by
failure to synchronize access to shared mutable data
. The value
1
was written to element
0
, then
overwritten
later by the value
11
. Also, when
writeIndex
was incremented to 3,
nothing was
written to that element
, as indicated by the 0 in that element of the printed array.
Recall that we added calls to
Thread
method
sleep
between operations on the shared
mutable data to emphasize the
unpredictability of thread scheduling
and increase the likeli-
hood of producing erroneous output. Even if these operations were allowed to proceed at
their normal pace, you could still see errors in the program's output. However, modern
processors can handle the simple operations of the
SimpleArray
method
add
so quickly
that you might not see the errors caused by the two threads executing this method concur-
rently, even if you tested the program dozens of times.
One of the challenges of multi-
threaded programming is spotting the errors—they may occur so infrequently and unpredictably
that a broken program does not produce incorrect results during testing, creating the illusion that
the program is correct.
This is all the more reason to use predefined collections that handle
the synchronization for you.