0

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

4

3 回答 3

4

Java 为多线程同步提供了广泛的 API,因此我强烈建议您不要尝试编写类似的东西,如果您不想在竞争条件的地狱中受苦受难。

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

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

根据您最后的评论,我有两个建议:

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

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

    • 它是一个可重入锁,因此如果一个线程已经获取,则后续尝试获取将是非阻塞的,它允许多个读取器进入,但只有一个写入器。
    • 每次需要将元素添加到并发集合中时,您都需要获取编写器,并在添加后释放它。此外,您必须在获取大小之前获取写入器锁,并在完成处理后释放它
于 2012-07-19T08:04:38.310 回答
3

安全起见,让它们同步。除非您能够为您提出的任何想法或此处可能提出的任何建议提出并发正确性证明,否则风险是不值得的。

编辑:我放弃了。我终于明白这很像一个共享读锁,甚至在阅读另一个这么说的答案之前;-)m1()声明一个共享读锁并m2()声明一个写锁。那么任意数量的m1()s可以同时运行但是m1()&m2()不能同时运行,并且没有两个m2()s可以同时运行。

于 2012-07-19T07:58:11.267 回答
2

我建议ReadWriteLock为此使用 a 。m1()readLock()和保护。m2()_writeLock()

于 2012-07-19T08:50:59.733 回答