Skip to main content
added 40 characters in body
Source Link
Gray
  • 117.2k
  • 24
  • 305
  • 360

how is it possible that while thread1 is executing the put() method acquiring the lock on the entire Hashtable, other thread2 can execute the containskey() method?

It's not possible. The issue here is not about Hashtable class itself which, as you point out, is a synchronized class so will not be corrupted. The race condition is that thread-A may test for a key that doesn't exist. But before it can do the put, thread-B tests for the same key that still doesn't exist. Then both threads put the same value into the table with one of them overwriting the other. This is the race.

1 if (! hashtable.contains(key)) { 2 hashtable.put(key, value); 3 } 

To enumerate the race more completely:

  1. Thread-A calls hashtable.contains("foo") which returns false on line #1.
  2. Thread-B runs then also calls hashtable.contains("foo") which also returns false on line #1.
  3. Thread-A calls hashtable.put("foo", "bar") on line 2.
  4. Thread-B calls hashtable.put("foo", "baz") on line 2.

If this happens in this order (and it certainly can), then Thread-B will overwrite Thread-A's value for "foo". Hashtable isn't corrupted but the overwrite may not have been expected by the logic of the code. It might also happen that 4 and 3 are reversed so Thread-A would overwrite Thread-B's value for "foo". The nature of a race condition is that thread run order cannot be predicted withoutand to ensure the right logic you need to apply specific locking.

Btw, Hashtable is an old class and has been superseded by ConcurrentHashMap. But the race condition would still exist with ConcurrentHashMap although it does have atomic operations like concurrentMap.putIfAbsent(key, value) for this reason. See ConcurrentMap javadocs.

how is it possible that while thread1 is executing the put() method acquiring the lock on the entire Hashtable, other thread2 can execute the containskey() method?

It's not possible. The issue here is not about Hashtable class itself which, as you point out, is a synchronized class so will not be corrupted. The race condition is that thread-A may test for a key that doesn't exist. But before it can do the put, thread-B tests for the same key that still doesn't exist. Then both threads put the same value into the table with one of them overwriting the other. This is the race.

1 if (! hashtable.contains(key)) { 2 hashtable.put(key, value); 3 } 

To enumerate the race more completely:

  1. Thread-A calls hashtable.contains("foo") which returns false on line #1.
  2. Thread-B runs then also calls hashtable.contains("foo") which also returns false on line #1.
  3. Thread-A calls hashtable.put("foo", "bar") on line 2.
  4. Thread-B calls hashtable.put("foo", "baz") on line 2.

If this happens in this order (and it certainly can), then Thread-B will overwrite Thread-A's value for "foo". Hashtable isn't corrupted but the overwrite may not have been expected by the logic of the code. It might also happen that 4 and 3 are reversed so Thread-A would overwrite Thread-B's value for "foo". The nature of a race condition is that thread run order cannot be predicted without specific locking.

Btw, Hashtable is an old class and has been superseded by ConcurrentHashMap. But the race condition would still exist with ConcurrentHashMap although it does have atomic operations like concurrentMap.putIfAbsent(key, value) for this reason. See ConcurrentMap javadocs.

how is it possible that while thread1 is executing the put() method acquiring the lock on the entire Hashtable, other thread2 can execute the containskey() method?

It's not possible. The issue here is not about Hashtable class itself which, as you point out, is a synchronized class so will not be corrupted. The race condition is that thread-A may test for a key that doesn't exist. But before it can do the put, thread-B tests for the same key that still doesn't exist. Then both threads put the same value into the table with one of them overwriting the other. This is the race.

1 if (! hashtable.contains(key)) { 2 hashtable.put(key, value); 3 } 

To enumerate the race more completely:

  1. Thread-A calls hashtable.contains("foo") which returns false on line #1.
  2. Thread-B runs then also calls hashtable.contains("foo") which also returns false on line #1.
  3. Thread-A calls hashtable.put("foo", "bar") on line 2.
  4. Thread-B calls hashtable.put("foo", "baz") on line 2.

If this happens in this order (and it certainly can), then Thread-B will overwrite Thread-A's value for "foo". Hashtable isn't corrupted but the overwrite may not have been expected by the logic of the code. It might also happen that 4 and 3 are reversed so Thread-A would overwrite Thread-B's value for "foo". The nature of a race condition is that thread run order cannot be predicted and to ensure the right logic you need to apply specific locking.

Btw, Hashtable is an old class and has been superseded by ConcurrentHashMap. But the race condition would still exist with ConcurrentHashMap although it does have atomic operations like concurrentMap.putIfAbsent(key, value) for this reason. See ConcurrentMap javadocs.

added 218 characters in body
Source Link
Gray
  • 117.2k
  • 24
  • 305
  • 360

how is it possible that while thread1 is executing the put() method acquiring the lock on the entire Hashtable, other thread2 can execute the containskey() method?

It's not possible. The issue here is not about Hashtable class itself which, as you point out, is a synchronized class so will not be corrupted. The race condition is that thread-A may test for a key that doesn't exist. But before it can do the put, thread-B tests for the same key that still doesn't exist. Then both threads put the same value into the table with one of them overwriting the other. This is the race.

1 if (! hashtable.contains(key)) { 2 hashtable.put(key, value); 3 } 

To enumerate the race more completely:

  1. Thread-A calls hashtable.contains("foo") which returns false on line #1.
  2. Thread-B runs then also calls hashtable.contains("foo") which also returns false on line #1.
  3. Thread-A calls hashtable.put("foo", "bar") on line 2.
  4. Thread-B calls hashtable.put("foo", "baz") on line 2.

If this happens in this order (and it certainly can), then Thread-B will overwrite Thread-A's value for "foo". Hashtable isn't corrupted but the overwrite may not have been expected by the logic of the code. It might also happen that 4 and 3 are reversed so Thread-A would overwrite Thread-B's value for "foo". The nature of a race condition is that thread run order cannot be predicted without specific locking.

Btw, Hashtable is an old class and has been superseded by ConcurrentHashMap. But the race condition would still exist with ConcurrentHashMap although it does have atomic operations like concurrentMap.putIfAbsent(key, value) for this reason. See ConcurrentMap javadocs.

how is it possible that while thread1 is executing the put() method acquiring the lock on the entire Hashtable, other thread2 can execute the containskey() method?

It's not possible. The issue here is not about Hashtable class itself which, as you point out, is a synchronized class so will not be corrupted. The race condition is that thread-A may test for a key that doesn't exist. But before it can do the put, thread-B tests for the same key that still doesn't exist. Then both threads put the same value into the table with one of them overwriting the other. This is the race.

1 if (! hashtable.contains(key)) { 2 hashtable.put(key, value); 3 } 

To enumerate the race more completely:

  1. Thread-A calls hashtable.contains("foo") which returns false on line #1.
  2. Thread-B runs then also calls hashtable.contains("foo") which also returns false on line #1.
  3. Thread-A calls hashtable.put("foo", "bar") on line 2.
  4. Thread-B calls hashtable.put("foo", "baz") on line 2.

If this happens in this order (and it certainly can), then Thread-B will overwrite Thread-A's value for "foo". Hashtable isn't corrupted but the overwrite may not have been expected by the logic of the code.

Btw, Hashtable is an old class and has been superseded by ConcurrentHashMap. But the race condition would still exist with ConcurrentHashMap although it does have atomic operations like concurrentMap.putIfAbsent(key, value) for this reason. See ConcurrentMap javadocs.

how is it possible that while thread1 is executing the put() method acquiring the lock on the entire Hashtable, other thread2 can execute the containskey() method?

It's not possible. The issue here is not about Hashtable class itself which, as you point out, is a synchronized class so will not be corrupted. The race condition is that thread-A may test for a key that doesn't exist. But before it can do the put, thread-B tests for the same key that still doesn't exist. Then both threads put the same value into the table with one of them overwriting the other. This is the race.

1 if (! hashtable.contains(key)) { 2 hashtable.put(key, value); 3 } 

To enumerate the race more completely:

  1. Thread-A calls hashtable.contains("foo") which returns false on line #1.
  2. Thread-B runs then also calls hashtable.contains("foo") which also returns false on line #1.
  3. Thread-A calls hashtable.put("foo", "bar") on line 2.
  4. Thread-B calls hashtable.put("foo", "baz") on line 2.

If this happens in this order (and it certainly can), then Thread-B will overwrite Thread-A's value for "foo". Hashtable isn't corrupted but the overwrite may not have been expected by the logic of the code. It might also happen that 4 and 3 are reversed so Thread-A would overwrite Thread-B's value for "foo". The nature of a race condition is that thread run order cannot be predicted without specific locking.

Btw, Hashtable is an old class and has been superseded by ConcurrentHashMap. But the race condition would still exist with ConcurrentHashMap although it does have atomic operations like concurrentMap.putIfAbsent(key, value) for this reason. See ConcurrentMap javadocs.

Source Link
Gray
  • 117.2k
  • 24
  • 305
  • 360

how is it possible that while thread1 is executing the put() method acquiring the lock on the entire Hashtable, other thread2 can execute the containskey() method?

It's not possible. The issue here is not about Hashtable class itself which, as you point out, is a synchronized class so will not be corrupted. The race condition is that thread-A may test for a key that doesn't exist. But before it can do the put, thread-B tests for the same key that still doesn't exist. Then both threads put the same value into the table with one of them overwriting the other. This is the race.

1 if (! hashtable.contains(key)) { 2 hashtable.put(key, value); 3 } 

To enumerate the race more completely:

  1. Thread-A calls hashtable.contains("foo") which returns false on line #1.
  2. Thread-B runs then also calls hashtable.contains("foo") which also returns false on line #1.
  3. Thread-A calls hashtable.put("foo", "bar") on line 2.
  4. Thread-B calls hashtable.put("foo", "baz") on line 2.

If this happens in this order (and it certainly can), then Thread-B will overwrite Thread-A's value for "foo". Hashtable isn't corrupted but the overwrite may not have been expected by the logic of the code.

Btw, Hashtable is an old class and has been superseded by ConcurrentHashMap. But the race condition would still exist with ConcurrentHashMap although it does have atomic operations like concurrentMap.putIfAbsent(key, value) for this reason. See ConcurrentMap javadocs.