septerr
septerr

Reputation: 6593

Java - Synchronized Object/Block

I am looking for clarification about synchronized blocks. Consider this class -

public class A{
Map map;

 public getValue(String key){
  return map.get(key);
 }

 public remove(String key){
  synchronized(map){
   map.remove(key);
  }
 }
}

A is a singleton. getValue is heavily accessed throughout the app by multiple threads. I am adding a new method, remove, that removes a key from the map. If remove is implemented as above,

  1. When a thread is in the synchronized block of the remove method, I assume it will acquire a lock on the map object. Does that mean other threads trying to access the map via the getValue method will be blocked? (I'd like them to.)
  2. When no thread is in the synchronized block of remove method, will threads accessing the getValue method function as usual i.e. not block each other? (I'd like that too).

I want the getValue threads to block only if there is a thread performing the remove operation.

Upvotes: 0

Views: 549

Answers (6)

Louis Wasserman
Louis Wasserman

Reputation: 198211

The one rule of synchronized is that only one thread can be in a synchronized(foo) block at a time, for the same foo. That's the only rule of synchronized.

Well, there's some complicated stuff about memory barriers and the like, and a single thread can be in several nested synchronized(foo) blocks for the same foo at the same time:

void thing() {
  synchronized(foo) {
    stuff(); // this works fine!
  }
}
void stuff() {
  synchronized(foo) {
    doMoreStuff();
  }
}

... but the rule stated above is basically the key to understanding synchronized.

Upvotes: 0

Morfic
Morfic

Reputation: 15518

If I understood correctly your need, you could take a look at the ConcurrentMap and of course ConcurrentHashMap which I believe was introduced with Java 5.0 and supports a level of concurrency.

Upvotes: 4

Dilum Ranatunga
Dilum Ranatunga

Reputation: 13374

You have a chicken and egg problem with

I want the getValue threads to block only if there is a thread performing the remove operation.

Without some sort of inter-thread interaction, you cannot figure out whether there is some other thread performing a remove.

The correct way to implement getValue(...) is to synchronize on the map.

I recommend dropping your own locking, and using a ConcurrentHashMap and utilizing a lot of work into concurrent performance.

Upvotes: 0

Kumar Vivek Mitra
Kumar Vivek Mitra

Reputation: 33544

1. getValue() is not synchronized, when a thread acquires the lock of an object, it has the control over all the synchronized blocks... not the Non-synchronized one.. So other threads can access the getValue() when as thread is in sychronized(map) block

2. Use HashTable, which is a sychronized MAP

Upvotes: 0

jtahlborn
jtahlborn

Reputation: 53694

You don't show how the Map instance is instantiated, but assuming it is not a thread-safe collection instance, this code is not thread-safe.

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1502046

When a thread is in the synchronized block of the remove method, I assume it will acquire a lock on the map object. Does that mean other threads trying to access the map via the getValue method will be blocked?

No. Which means you've got a problem, unless you happen to be using a thread-safe map implementation.

When no thread is in the synchronized block of remove method, will threads accessing the getValue method function as usual i.e. not block each other? (I'd like that too).

They won't block each other, no. Again, you'll need to make sure that's okay with whichever Map implementation you're using, although it's much more likely to be okay than reading at the same time as writing.

You should consider using a ConcurrentMap implementation (e.g. ConcurrentHashMap), at which point you don't need any synchronization at all.

If you can't use that, I'd recommend synchronizing in both getValue and remove - and measuring the performance. Acquiring an uncontended lock is reasonably cheap - do you really need to go lock-free? (Using ConcurrentHashMap is a fairly simple way of avoiding the issue, of course, but you should always consider whether extra complexity is needed to achieve the performance you require before you start micro-optimizing.)

Upvotes: 4

Related Questions