我有以下用例:我有一个类有两个方法m1和m2。通常,m1()不需要同步,但是如果有人调用m2(),那么只要执行m2(),m1()就需要同步。为了实现这一点,我想出了以下代码。你能来吗?评论并提出更好的选择?
注意:我意识到这种情况不切实际,因为例如如果某个线程在m1的中间,而其他一些线程调用m2,那么就会出现问题(如果有人指出如何处理它会很好);尽管如此,我发现这个很有意思。
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;
}
}
}
编辑:实际问题是:我正在设计一个对象池,在那里我需要知道有多少和哪些对象被发出,剩下多少。所以我想维护两个集合:origSet将是一个包含所有对象的HashSet,而dynaSet将是一个ConcurrentSkipListSet,我从中提供对象并将它们放回去。如果我需要弄清楚origSet和dynaSet之间的区别一瞬间,我需要'冻结'dyanSet直到计算出差异。但是,获得这种差异将是一个非常罕见的操作,因此我的问题。
答案 0 :(得分:4)
Java有一个用于多线程同步的广泛API,所以我热烈建议你不要尝试写这样的东西,如果你不想在竞争条件下死去的话。
如果您已经阅读了这本书http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz,那么您现在应该:
根据你上次的评论,我有两个建议:
如果您只需要获取集合的大小,而不是使用数据对集合执行任何操作。我认为你根本不需要同步。您对getDynaSize的调用将返回最后一个可用值:当您使用它时不确定它是否是当前值,但除非您在处理方法中清楚地看到竞争条件,否则根本不要同步。 (也许你想给我们更多细节?)
如果您确实需要锁定,请使用ReadWriteLock,
答案 1 :(得分:3)
安全,让它们同步。除非你能够为你提出的任何内容提出同时的正确性证明,或者在这里提出的任何建议,否则风险是不值得的。
m1()
声明共享读锁定并让m2()
声称写一个锁。然后可以同时运行任意数量的m1()s
m1()
& m2()
无法同时运行,并且没有两个m2()s
可以同时运行。
答案 2 :(得分:2)
我建议使用ReadWriteLock
。使用m1()
保护readLock()
,m2()
保护writeLock()
。