简体   繁体   English

同步与ReadWriteLock

[英]synchronized vs ReadWriteLock

Hi i have extremly simplified a java problem in the following code snippet 嗨,我在以下代码段中极大地简化了Java问题

public class WhichJavaSynchroIsBestHere {

    private BlockingQueue<CustomObject> queue = new PriorityBlockingQueue<CustomObject>();

    public void add( CustomObject customO ) {

        // The custom objects do never have the same id
        // so it's no horizontal concurrency but more vertical one a la producer/consumer
        if ( !queue.contains( customO ) ) {
            // Between the two statement a remove can happen
            queue.add( customO );
        }
    }

    public void remove( CustomObject customO ) {
        queue.remove( customO );
    }

    public static class CustomObject {
        long id;
        @Override
        public boolean equals( Object obj ) {
            if ( obj == null || getClass() != obj.getClass() )
                return false;
            CustomObject other = (CustomObject) obj;
            return ( id == other.id;
        }
    }
}

So this more of producer / consumer problem because presumably the two thread calling add do not pass the same Customobject (id), but this can happen when if one thread is calling add with same object as a second thread calling remove. 因此,这更多的生产者/使用者问题,因为大概两个调用add的线程不会传递相同的Customobject (id),但是如果一个线程正在调用add且对象与另一个线程调用remove的对象相同,则可能会发生这种情况。 The code section in between the if condition and the adding is what seems to me as not thread, safe, i was thinking about the object Lock (no synchronized blocks) to secure that section, but is a ReadWriteLock better? 在if条件和添加之间的代码段在我看来不是线程,安全,我在考虑对象Lock(无synchronized块)来保护该段,但是ReadWriteLock更好吗?

It would make no difference, as both sections would require a Write lock anyway. 这没有什么区别,因为无论如何这两个部分都需要写锁定。

The advantage of a ReadWriteLock is to easily allow multiple Readers that can work with shared access, and, yet, cooperate well with someone who requires exclusive access for Writing. ReadWriteLock的优点是可以轻松地允许可以使用共享访问权限的多个Reader,并且与需要独占访问权限才能进行写作的人员很好地合作。

You could surround the contains code with a Read lock, and that would make sense if putting in potential duplicates is the bulk of your work. 您可以在“ contains代码的周围加上“读取”锁定,如果您将大量重复工作放在可能的工作中,那将是有道理的。 But if it's more a sanity check for a rare edge case, than a primary driver of your work (ie the test will pass the vast majority of the time), then there's no reason for the Read lock in this case. 但是,如果比起工作的主要驱动因素(而不是测试的大部分时间都通过了),这更是一种针对极端情况的健全性检查,那么在这种情况下就没有理由进行读取锁定。 Just lock the whole section and be done with it. 只需锁定整个部分并完成即可。

The code section in between the if condition and the adding is what seems to me as not thread-safe 在if条件和添加之间的代码段对我来说似乎不是线程安全的

You are correct, it isn't thread-safe. 您是正确的,它不是线程安全的。 Anytime you have multiple calls to a object, even a synchronized one, you need to worry about the state of the object changing between the calls if accessed by multiple threads. 每当对一个对象进行多次调用(甚至是synchronized调用)时,如果多个线程访问该对象,则需要担心两次调用之间对象的状态会发生变化。 It's not just than an object might have been removed, but a duplicate object could have been added by a different producer causing duplicates in the queue. 不仅仅是对象可能已被删除,而且另一个生产者可能添加了重复的对象,从而导致队列中出现重复。 The race would be: 比赛将是:

  1. thread #1 tests to see if object A is in the queue, it's not 线程#1测试以查看对象A是否在队列中,不是
  2. thread #2 tests to see if object A is in the queue, it's not 线程#2测试以查看对象A是否在队列中,不是
  3. thread #1 adds object A to the queue 线程#1将对象A添加到队列中
  4. thread #2 adds object A to the queue 线程#2将对象A添加到队列中

The queue would then have 2 copies of A in it. 队列中将有2个A副本。

i was thinking about the object Lock (no synchronized blocks) to secure that section 我在考虑对象锁(无同步块)以保护该部分

If you are shying away from synchronized because of perceived performance problems, then don't. 如果您由于察觉到的性能问题而避开了synchronized ,那么请不要这样做。 This is a perfect example of where using synchronized is appropriate. 这是适合使用synchronized的最佳示例。 You could get rid of the BlockingQueue if you are doing all operations inside of a synchronized block. 如果您在synchronized块内执行所有操作,则可以摆脱BlockingQueue

is a ReadWriteLock better ? ReadWriteLock更好吗?

No because in both cases, the threads are "writing" to the queue. 否,因为在两种情况下,线程都是“写入”队列。 A removal is modifying the queue as much as an add. 删除将修改队列与添加队列一样多。 The ReadWriteLock allows multiple reading threads if there is no writers but exclusive access to a writing thread. 如果没有作者,但对写线程具有独占访问权,则ReadWriteLock允许多个阅读线程。 Now the testing of the queue is considered a read but that's not going to save you very much unless there are is a large percentage of times where there are duplicates that are already in the queue. 现在,对队列的测试被视为已读,但这不会为您节省很多,除非在很大的情况下,队列中已经存在重复项。

Also, be very careful of queue.contains(customO) . 另外,要非常注意queue.contains(customO) Most queues (this includes PriorityBlockingQueue ) run through all items in the queue to look for the one you may be adding ( O(N) ). 大多数队列(包括PriorityBlockingQueue )在队列中的所有项目中运行,以查找您可能要添加的项目( O(N) )。 This can be very expensive depending on how many items are in the collection. 这可能非常昂贵,具体取决于集合中有多少个项目。

This feels to me to be be a good place to use the ConcurrentSkipListSet . 在我看来,这是使用ConcurrentSkipListSet的好地方。 You just do an queue.add() which internally does a put-if-absent. You can do a 您只需执行一个queue.add()即可which internally does a put-if-absent. You can do a which internally does a put-if-absent. You can do a queue.pollFirst()` to remove and get the first item. which internally does a put-if-absent. You can do a queue.pollFirst()`删除并获取第一项。 The collection then takes care of the memory synchronization and locking for you and resolves the race conditions. 然后,该集合将为您处理内存同步和锁定,并解决争用条件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM