Reputation: 7226
I have the following use case: I have a class that has two methods m1 and m2. Normally, m1() need not be synchronized, however if someone calls m2(), then m1() needs to be synchronized as long as m2() is being executed. In order to achieve this, I came up with the following code. Could you pl. comment on it and suggest better options?
Note: I realize that this situation is not practical, because e.g. if some thread is in the middle of m1 and some other thread calls m2, then there would be a problem (and it would be great if someone points out how to take care of that); nonetheless I found thinking about this interesting.
public class DynamicSync
{
volatile MyLock lock;
private final MyLock DUMMY_LOCK = new DummyMyLock();
private final MyLock SYNCHRONIZED_LOCK = new SynchronizedMyLock();
public DynamicSync()
{
lock = DUMMY_LOCK;
}
public void dynamicallySynchronizedMethod() // this is method m1() in the question above
{
lock.lock();
// some logic
lock.unlock();
}
public void setLockAndExecuteLogic() // this is method m2() in the question above
{
synchronized(SYNCHRONIZED_LOCK)
{
lock = SYNCHRONIZED_LOCK;
// some logic
}
}
interface MyLock
{
void lock();
void unlock();
}
class DummyMyLock implements MyLock
{
@Override
public void lock()
{
}
@Override
public void unlock()
{
}
}
class SynchronizedMyLock implements MyLock
{
@Override
public synchronized void lock()
{
// no op
}
@Override
public void unlock()
{
lock = DUMMY_LOCK;
}
}
}
EDIT: the actual problem is: I'm designing an object pool, where I need to know how many and which of the objects are given out, and how many remain. So I was thinking of maintaining two collections: origSet would be a HashSet that contains all the objects and dynaSet would be a ConcurrentSkipListSet from which I give out objects and put them back in. If I need to figure out the difference between origSet and dynaSet at an instant, I need to 'freeze' dyanSet till the difference is calculated. But getting this difference will be a very infrequent operation, hence my question.
Upvotes: 0
Views: 1798
Reputation: 310869
Be safe, make them both synchronized. Unless you are capable of coming up with a concurrent correctness proof for whatever you come up with, or whatever may be suggested here, the risk is not worth it.
EDIT: I recant. It finally dawned on me that this is rather like a shared-read lock, even before reading the other answer that says so ;-) Make m1()
claim a shared-read lock and makem2()
claim a write lock. Then any number of m1()s
can run simultaneously but m1()
& m2()
can't run at the same time, and no two m2()s
can run at the same time.
Upvotes: 3
Reputation: 20080
Java has an extensive API for multi-threading Synchronization so I warmly suggest you don't try writing anything like that if you do not want to die suffering in the hell of race conditions.
If you have already read the book http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz , then you should now:
According to your last comments, I have two proposals:
If you just need to get the size of the collection, but not doing anything on the collection using the data. I do not think you need to synchronize at all. Your call to getDynaSize will return the last available value: not sure it is the current one when you will use it, but unless you clearly see race conditions inside your processing method, do not synchronize at all. (maybe you want to give us more details?)
If you really need to lock, use a ReadWriteLock,
Upvotes: 4
Reputation: 46209
I would suggest using a ReadWriteLock
for this. Protect m1()
with the readLock()
and m2()
with the writeLock()
.
Upvotes: 2