如何确保多个线程可以安全地访问类字段?

发布于 2024-07-05 17:11:19 字数 298 浏览 14 评论 0原文

当多个线程通过 getter 方法访问类字段时,如何维护线程安全? 同步关键字足够吗?

这安全吗:

public class SomeClass {
    private int val;

    public synchronized int getVal() {
        return val;
    }

    private void setVal(int val) {
        this.val = val;
    }
}

还是设置器会带来更多的并发症?

When a class field is accessed via a getter method by multiple threads, how do you maintain thread safety? Is the synchronized keyword sufficient?

Is this safe:

public class SomeClass {
    private int val;

    public synchronized int getVal() {
        return val;
    }

    private void setVal(int val) {
        this.val = val;
    }
}

or does the setter introduce further complications?

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

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

发布评论

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

评论(6

天煞孤星 2024-07-12 17:11:19

如果您也在此处的 setter 上使用“同步”,则此代码是线程安全的。 然而,它可能不够细化; 如果您有 20 个 getter 和 setter,并且它们全部同步,则可能会造成同步瓶颈。

在这个特定的实例中,使用单个 int 变量,然后消除“同步”并将 int 字段标记为“易失性”也将确保可见性(每个线程在调用 getter 时将看到“val”的最新值),但它可能不会足够同步以满足您的需求。 例如,

 int old = someThing.getVal();
 if (old == 1) {
    someThing.setVal(2);
 }

当且仅当 val 已经为 1 时,期望将 val 设置为 2 是不正确的。 为此,您需要一个外部锁或某种原子比较和设置方法。

我强烈建议您阅读 Brian Goetz 等人编写的 Java Concurrency In Practice,它对 Java 的并发结构有最好的介绍。

If you use 'synchronized' on the setter here too, this code is threadsafe. However it may not be sufficiently granular; if you have 20 getters and setters and they're all synchronized, you may be creating a synchronization bottleneck.

In this specific instance, with a single int variable, then eliminating the 'synchronized' and marking the int field 'volatile' will also ensure visibility (each thread will see the latest value of 'val' when calling the getter) but it may not be synchronized enough for your needs. For example, expecting

 int old = someThing.getVal();
 if (old == 1) {
    someThing.setVal(2);
 }

to set val to 2 if and only if it's already 1 is incorrect. For this you need an external lock, or some atomic compare-and-set method.

I strongly suggest you read Java Concurrency In Practice by Brian Goetz et al, it has the best coverage of Java's concurrency constructs.

棒棒糖 2024-07-12 17:11:19

除了 Cowan 的评论< /a>,您可以执行以下操作来进行比较和存储:

synchronized(someThing) {
    int old = someThing.getVal();
    if (old == 1) {
        someThing.setVal(2);
    }
}

这有效,因为通过同步方法定义的锁与对象的锁隐式相同(请参阅 Java 语言规范)。

In addition to Cowan's comment, you could do the following for a compare and store:

synchronized(someThing) {
    int old = someThing.getVal();
    if (old == 1) {
        someThing.setVal(2);
    }
}

This works because the lock defined via a synchronized method is implicitly the same as the object's lock (see java language spec).

假扮的天使 2024-07-12 17:11:19

根据我的理解,您应该在 getter 和 setter 方法上使用同步,这就足够了。

编辑:这是一个链接,指向一些更多信息关于同步和什么不是。

From my understanding you should use synchronized on both the getter and the setter methods, and that is sufficient.

Edit: Here is a link to some more information on synchronization and what not.

み青杉依旧 2024-07-12 17:11:19

如果您的类仅包含一个变量,那么实现线程安全的另一种方法是使用现有的 AtomicInteger 对象。

public class ThreadSafeSomeClass {

    private final AtomicInteger value = new AtomicInteger(0);

    public void setValue(int x){
         value.set(x);
    }

    public int getValue(){
         return value.get();
    }

}

但是,如果您添加其他变量以使它们相互依赖(一个变量的状态取决于另一个变量的状态),则 AtomicInteger 将不起作用。

赞同阅读《Java 并发实践》的建议。

If your class contains just one variable, then another way of achieving thread-safety is to use the existing AtomicInteger object.

public class ThreadSafeSomeClass {

    private final AtomicInteger value = new AtomicInteger(0);

    public void setValue(int x){
         value.set(x);
    }

    public int getValue(){
         return value.get();
    }

}

However, if you add additional variables such that they are dependent (state of one variable depends upon the state of another), then AtomicInteger won't work.

Echoing the suggestion to read "Java Concurrency in Practice".

月牙弯弯 2024-07-12 17:11:19

对于简单的对象来说这可能就足够了。 在大多数情况下,您应该避免使用synchronized 关键字,因为您可能会遇到同步死锁。

示例:

public class SomeClass {

  private Object mutex = new Object();
  private int    val   = -1; // TODO: Adjust initialization to a reasonable start
                             //       value
  public int getVal() {
    synchronized ( mutex ) {
      return val;
    }
  }

  private void setVal( int val ) {
    synchronized ( mutex ) {
      this.val = val;
    }
  }
}

确保只有一个线程读取或写入本地实例成员。

阅读《Java并发编程(tm):设计原则和模式(Java (Addison-Wesley))》一书,也许http://java.sun.com/docs/books/tutorial/essential/concurrency/index.html 也很有帮助...

For simple objects this may suffice. In most cases you should avoid the synchronized keyword because you may run into a synchronization deadlock.

Example:

public class SomeClass {

  private Object mutex = new Object();
  private int    val   = -1; // TODO: Adjust initialization to a reasonable start
                             //       value
  public int getVal() {
    synchronized ( mutex ) {
      return val;
    }
  }

  private void setVal( int val ) {
    synchronized ( mutex ) {
      this.val = val;
    }
  }
}

Assures that only one thread reads or writes to the local instance member.

Read the book "Concurrent Programming in Java(tm): Design Principles and Patterns (Java (Addison-Wesley))", maybe http://java.sun.com/docs/books/tutorial/essential/concurrency/index.html is also helpful...

清浅ˋ旧时光 2024-07-12 17:11:19

同步的存在是为了防止线程干扰和内存一致性错误。 通过在 getVal() 上进行同步,代码可以保证 SomeClass 上的其他同步方法不会同时执行。 由于没有其他同步方法,因此它没有提供太多价值。 另请注意,对原语的读取和写入具有原子访问权限。 这意味着通过仔细编程,不需要同步对该字段的访问。

请阅读同步

不太清楚为什么这个值下降到-3。 我只是总结 Sun 的同步教程的内容(以及我自己的经验)。

使用简单的原子变量访问是
比访问这些更有效
通过同步代码的变量,
但需要更多的照顾
程序员避免内存一致性
错误。 是否需要额外的努力
值得取决于大小和
应用程序的复杂性。

Synchronization exists to protect against thread interference and memory consistency errors. By synchronizing on the getVal(), the code is guaranteeing that other synchronized methods on SomeClass do not also execute at the same time. Since there are no other synchronized methods, it isn't providing much value. Also note that reads and writes on primitives have atomic access. That means with careful programming, one doesn't need to synchronize the access to the field.

Read Sychronization.

Not really sure why this was dropped to -3. I'm simply summarizing what the Synchronization tutorial from Sun says (as well as my own experience).

Using simple atomic variable access is
more efficient than accessing these
variables through synchronized code,
but requires more care by the
programmer to avoid memory consistency
errors. Whether the extra effort is
worthwhile depends on the size and
complexity of the application.

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