Java:如何动态同步方法

时间:2012-07-19 07:55:44

标签: java synchronization

我有以下用例:我有一个类有两个方法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直到计算出差异。但是,获得这种差异将是一个非常罕见的操作,因此我的问题。

3 个答案:

答案 0 :(得分:4)

Java有一个用于多线程同步的广泛API,所以我热烈建议你不要尝试写这样的东西,如果你不想在竞争条件下死去的话。

如果您已经阅读了这本书http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz,那么您现在应该:

  • 最好的解决方案是保持不变,并在您的世界中解决线程同步问题。
  • 如果您无法保持不变,请保持防御,并在分享内部属性时制作防御性副本。这被称为“安全出版物”
  • 如果你不能保持不变,请至少尝试使用并发集合来让你的生活更轻松。
  • 如果您真的需要开发自己的锁定系统,请查看Java ReadWriteLock。

根据你上次的评论,我有两个建议:

  1. 如果您只需要获取集合的大小,而不是使用数据对集合执行任何操作。我认为你根本不需要同步。您对getDynaSize的调用将返回最后一个可用值:当您使用它时不确定它是否是当前值,但除非您在处理方法中清楚地看到竞争条件,否则根本不要同步。 (也许你想给我们更多细节?)

  2. 如果您确实需要锁定,请使用ReadWriteLock,

    • 这是一个可重入的锁,所以如果一个线程已经获得,后续尝试获取将是非阻止,它允许多个读者进入,但只允许一个作者。
    • 每次需要向并发集合添加元素时都需要获取编写器,并在添加后释放它。而且,你必须在获得大小之前获取编写器锁,并在完成处理后释放它

答案 1 :(得分:3)

安全,让它们同步。除非你能够为你提出的任何内容提出同时的正确性证明,或者在这里提出的任何建议,否则风险是不值得的。

编辑:我放弃了。最后我突然意识到这就像是一个共享读锁,甚至在阅读其他答案之前就已经这样了;-)让m1()声明共享读锁定并让m2()声称写一个锁。然后可以同时运行任意数量的m1()s m1()& m2()无法同时运行,并且没有两个m2()s可以同时运行。

答案 2 :(得分:2)

我建议使用ReadWriteLock。使用m1()保护readLock()m2()保护writeLock()