爪哇。如何正确同步 getter 和 setter?

发布于 2024-09-06 21:59:53 字数 500 浏览 4 评论 0原文

如果我在一个对象中有多个可变属性,并且将由多个线程对其进行操作,那么我知道它们应该是同步的。

class Doggie {
    private String name;
    private int    age;

    public void setName(String name) { this.name = name; }
    public String getName() { return this.name; }
    public void setAge(int age) { this.age = age; }
    public int getAge() { return this.age; }

}

问题:

  • Java中的return和赋值不是原子操作吗?
  • 由于属性不一定是相互关联的,因此与同一锁同步并不总是有意义。如何组织锁定结构?
  • 使用内在锁还是私有对象锁模式更好?

If I have several mutable properties in an object that will be acted upon by several threads, I understand they should be synchronized.

class Doggie {
    private String name;
    private int    age;

    public void setName(String name) { this.name = name; }
    public String getName() { return this.name; }
    public void setAge(int age) { this.age = age; }
    public int getAge() { return this.age; }

}

Questions:

  • Are not return and assignment atomic operations in Java?
  • Since properties might not necessarily be interrelated, it does not always make sense to synchronize with the same lock. How to organize the locking structure?
  • Is it better to go with the intrinsic lock or a private Object lock pattern?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

清风挽心 2024-09-13 21:59:53
  • Java 中的返回和赋值不是原子操作吗?

是的,它们是原子性的(至少在某些情况下),但原子性并不是唯一的问题。另一个重要问题是,是否保证一个线程对属性的写入操作对于不同线程对同一属性进行的后续读取可见。

  • 当读和写在同一个线程中时,读保证看到更早的写。

  • 当读取和写入在不同的线程中时,只有在两个线程正确同步或者属性声明为易失性的情况下,才能保证读取能看到较早的写入。

请注意,原始锁/互斥锁并不是同步的唯一方法。

  • 由于属性不一定是相互关联的,因此使用同一个锁进行同步并不总是有意义。如何组织锁定结构?

当(且仅当)可能发生锁争用时,使用多个锁才有意义。在您的示例中,只有当某些 Doggie 实例接收到非常高的获取和/或设置操作率时,锁争用才可能成为问题。

  • 使用内在锁还是私有对象锁模式更好?

这取决于。如果您的应用程序要使用 Doggie 对象的原始锁,那么您可能会遇到锁争用,甚至可能会意外锁定 get 和 set 操作。在这种情况下,建议使用私人锁。否则,私有锁是不必要的开销。

  • Are not return and assignment atomic operations in Java?

Yes they are atomic (in some cases at least), but atomicity is not the only issue. Another important issue is whether the action of a write to an attribute by one thread is guaranteed to be visible to a following read for the same attribute made by a different thread.

  • When the reads and writes are in the same thread, the read is guaranteed to see the earlier write.

  • When the reads and writes are in different threads, the read is only guaranteed to see the earlier write if the two threads synchronize properly ... or if the attribute is declared as volatile.

Note that primitive locks/mutexes are not the only way to synchronize.

  • Since properties might not necessarily be interrelated, it does not always make sense to synchronize with the same lock. How to organize the locking structure?

It makes sense to use multiple locks if (and only if) lock contention is likely. In your example, lock contention is only likely to be an issue if some Doggie instance receives a very high rate of get and/or set operations.

  • Is it better to go with the intrinsic lock or a private Object lock pattern?

It depends. If your application is going use the Doggie object's primitive lock, then you might get lock contention or even unintended locking out of get and set operations. In that case a private lock might be advisable. Otherwise, a private lock is an unnecessary overhead.

听不够的曲调 2024-09-13 21:59:53

使用引用的操作是原子的,但不是易失性的 - 您将始终看到旧值或新值,但不能保证您会在没有某种内存屏障的情况下看到新值。我不记得哪些原语保证是原子的细节——可能除了长和双精度外。

就我个人而言,我会使用单个私人锁,直到我看到任何证据表明它是瓶颈。我建议不要锁定“this”,因为其他代码也可能锁定它。如果您是唯一了解锁的代码,那么就很难受到干扰。话虽如此,如果调用者想要以原子方式更改多个属性,您可能需要通过属性公开锁。

您确实需要线程安全的可变类型吗?如果你能避免这个要求,生活就会变得更简单。

Operations with references are atomic, but not volatile - you will always see the old value or the new value, but there's no guarantee you'll see the new value without some sort of memory barrier. I can't remember the details of which primitives are guaranteed to be atomic - probably all but long and double.

Personally I'd use a single private lock until I saw any evidence that it was a bottleneck. I would advise against locking on "this" as other code might lock on it too. If you're the only code that knows about the lock, it's harder to get interference. Having said that, if callers want to atomically change more than one property, you may want to expose the lock via a property.

Do you definitely need a threadsafe mutable type? If you could avoid that requirement it would make life simpler.

千秋岁 2024-09-13 21:59:53
  • 它们是原子操作,但描绘了两个客户端尝试同时获取和设置一段数据的场景。无法保证事物将被调用的顺序,这可能会极大地影响应用程序的结果。 (典型的例子是金钱交易。)
  • 使用同一个锁进行同步可能有意义,也可能没有意义——这实际上取决于您的应用程序。但是,如果没有必要,将整个对象锁定通常不是一个好主意。
  • 正如乔恩所说,从一个私人锁开始,然后根据结果从那里开始。
  • They are atomic operations, but picture a scenario where two clients are trying to get and set a piece of data at the same time. There is no guarantee as to which order things are going to be called which could greatly affect the results of your application. (The classic example is money transactions.)
  • It may or may not make sense to synchronize with the same lock - that really depends on your application. However, it typically is not a good idea to lock the entire object out if it is not necessary.
  • As with what Jon said, start with a single, private lock and go from there depending on results.
七月上 2024-09-13 21:59:53

您注意到不相关的属性可以有不同的锁是正确的。考虑到锁定对象需要少量内存,我个人会为每个属性使用一个锁,而不是为整个对象使用一个锁。

执行此操作的轻量级方法只是在写入属性时设置一个布尔值,否则清除该值。支持超时等的重量级方法是使用互斥锁。

You're right to take note that non-interrelated properties can have different locks. Considering that locking objects require trivial memory, I would personally go with a lock per property instead of one for the entire object.

The lightweight way to do this is just to have a boolean that's set while the property is being written to and clear otherwise. The heavyweight way to do this, to support timeouts etc., is with a mutex.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文