Java Reference
In-Depth Information
158 }
159 }
160
161 log.exiting("DvdFileAccess", "getDvdList");
162 return returnValue;
163 }
As with the file itself, the map of UPC numbers to file locations is a single object used by
many threads. However, in most cases, the threads will only be reading from the
recordNumbers
map—it will be much rarer for a method to update this map. Prior to JDK 5, we would have
synchronized all access to the
recordNumbers
map, which would have meant that only one
thread could ever access it at any given time. With JDK 5 we now have
ReadWriteLock
s that
allow for greater concurrency. Instead of synchronizing code, we encapsulate the code inside
calls to
lock
and
unlock
methods. Multiple threads can own a read lock on a single object at
any given time, but only one thread can own a write lock at any given time.
If we are running this from the constructor, then we will be updating the
recordNumbers
map, so we will not want any other thread to be accessing the map in the meantime—a write
lock will ensure this for us. This is set in line 136, and released in the finally block at line 157.
It is important to ensure that the lock is released even if an exception is thrown; hence the call
to unlock is in the finally block to ensure it is always run. This is recommended whenever you
are using the new locking classes.
Line 150 adds our UPC string and the location in the file into the map. Using generics and
autoboxing (introduced in Chapter 2) allows us to keep this code simple, while simultaneously
ensuring that invalid data is not entered into our
recordNumbers
map. At the very start of the
class we declared that the
recordNumbers
could only contain a
String
as the key and a
Long
as
the value with the following code:
51 private static Map<String, Long> recordNumbers
52 = new HashMap<String, Long>();
The compiler will then use this to validate
at compile time
that we are storing
String
s as
the key and a
Long
as the value within this
Map
. Using autoboxing allows us to add a
String
and
a
primitive
long
to the
Map
, knowing that Java will automatically convert the
primitive
long
to
the wrapper
Long
class required for the
Map
.
Prior to JDK 5, there was no way for the compiler to validate that the type of data we were
adding to a collection was the type of data we actually wanted to allow into the collection. You
will now get an error message if you attempt to add the wrong type of data to our collection.
If you would like to see an example of how this works, try changing line 150 as follows:
recordNumbers.put(dvd.getUPC(), (int) locationInFile);
The JDK 5 Java compiler will now produce an error message, because the type of data we
are potentially adding to the
Map
no longer matches our declared allowable contents:
sampleproject\db\DvdFileAccess.java:150: put(java.lang.String,java.lang.Long)
in java.util.Map<java.lang.String,java.lang.Long> cannot be applied to
(java.lang.String,int)
recordNumbers.put(dvd.getUPC(), (int) locationInFile);
^
1 error