...
Code Block |
---|
|
class RaceCollection implements Runnable {
private List<InetAddress>List<InetAddress> ips = Collections.synchronizedList(new ArrayList<InetAddress>ArrayList<InetAddress>());
public void addIPAddress(InetAddress ia) {
synchronized(ips) {
ips.add(ia);
}
}
public void removeIPAddress(InetAddress ia) {
synchronized(ips) {
ips.remove(ia);
}
}
public void nonAtomic() throws InterruptedException {
InetAddress[] ia;
synchronized(ips) {
ia = (InetAddress[]) ips.toArray(new InetAddress[0]);
}
// This statement should be in the synchronized block above
System.out.println(""Number of IPs: "" + ia.length);
}
public void run() {
try {
addIPAddress(InetAddress.getLocalHost());
nonAtomic();
} catch (UnknownHostException e) { /* Forward to handler */ }
catch (InterruptedException e) { /* Forward to handler */ }
}
public static void main(String[] args) {
RaceCollection rc1 = new RaceCollection();
for(int i = 0; i << 2; i++) {
new Thread(rc1).start();
}
}
}
|
...
Code Block |
---|
|
synchronized(ips) {
ia = (InetAddress[]) ips.toArray(new InetAddress[0]);
System.out.println(""Number of IPs: "" + ia.length);
}
|
Note that this advice applies to all Collection
classes including the thread-safe Hashtable
class. Enumerations of the objects of a Collection
and iterators also require explicit synchronization on the Collection
object or any single lock object.
...
Code Block |
---|
|
class CompositeCollection implements Runnable {
private List<InetAddress>List<InetAddress> ips = Collections.synchronizedList(new ArrayList<InetAddress>ArrayList<InetAddress>());
public CompositeCollection(List<InetAddress>List<InetAddress> list) {
this.ips = list;
}
public synchronized void addIPAddress(InetAddress ia) {
ips.add(ia);
}
// Other methods
public synchronized void atomic() throws InterruptedException {
InetAddress[] ia;
ia = (InetAddress[]) ips.toArray(new InetAddress[0]);
System.out.println(""Number of IPs: "" + ia.length);
}
}
|
Wiki Markup |
---|
Yet another method is to extend the base class and synchronize on the method that is desired to be atomic, however, it is not recommended because it goes against the spirit of limiting class extension ([OBJ33-J. Limit the extensibility of non-final classes and methods to only trusted subclasses]). Moreover, Goetz et al. \[[Goetz 06|AA. Java References#Goetz 06]\] cite other reasons: |
...
Code Block |
---|
|
public class KeyedCounter {
private Map<StringMap<String, Integer>Integer> map =
Collections.synchronizedMap(new HashMap<StringHashMap<String, Integer>Integer>());
public void increment(String key) {
Integer old = map.get(key);
int value = (old == null) ? 1 : old.intValue() + 1;
map.put(key, value);
}
public Integer getCount(String key) {
return map.get(key);
}
}
|
...
Code Block |
---|
|
public class KeyedCounter {
private Map<String,Integer>Map<String,Integer> map = new HashMap<String,Integer>()HashMap<String,Integer>();
public synchronized void increment(String key) {
Integer old = map.get(key);
int value = (old == null) ? 1 : old.intValue()+1;
map.put(key, value);
}
public synchronized Integer getCount(String key) {
return map.get(key);
}
}
|
...
Code Block |
---|
|
public class KeyedCounter {
private final ConcurrentMap<StringConcurrentMap<String, AtomicInteger>AtomicInteger> map =
new ConcurrentHashMap<StringConcurrentHashMap<String, AtomicInteger>AtomicInteger>();
public void increment(String key) {
AtomicInteger value = new AtomicInteger(0);
AtomicInteger old = map.putIfAbsent(key, value);
if (old != null) {
value = old;
}
value.incrementAndGet(); // Increment the value atomically
}
public Integer getCount(String key) {
AtomicInteger value = map.get(key);
return (value == null) ? null : value.get();
}
}
|
...
Wiki Markup |
---|
\[[API 06|AA. Java References#API 06]\] Class Vector, Class WeakReference
\[[JavaThreads 04|AA. Java References#JavaThreads 04]\] 8.2 ""Synchronization and Collection Classes""
\[[Goetz 06|AA. Java References#Goetz 06]\] 4.4.1. Client-side Locking, 4.4.2. Composition and 5.2.1. ConcurrentHashMap
\[[Lee 09|AA. Java References#Lee 09]\] ""Map & Compound Operation"" |
...
CON37-J. Never apply a lock to methods making network calls 11. Concurrency (CON) CON39-J. Ensure atomicity of 64-bit operations