同步跨线程共享但未并行访问的对象 [英] Synchronizing an object shared across threads, but not accessed concurrently

查看:117
本文介绍了同步跨线程共享但未并行访问的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个与 data 字段的共享对象。多个线程将共享对此对象的引用以访问该字段。线程从不会同时访问对象。我需要将数据声明为volatile吗?

Let's say I have a shared object with field data. Multiple threads will share a reference to this object in order to access the field. The threads never access the object concurrently, though. Do I need to declare data as volatile?

这种情况如下:


  • 一个类计数器定义一个唯一字段 value 和一个方法 increment

  • 线程递增计数器,然后产生另一个线程使计数器递增等。

  • A class Counter defines a unique field value and one method increment.
  • A thread increments the counter, then spawn another thread that increments the counter, etc.

给定了程序的逻辑,没有并发访问计数器。然而,计数器是跨多个线程共享的。计数器必须是一个易变的吗?

Given the very logic of the program, there is no concurrent access to the counter. The counter is however shared accross multiple threads. Must the counter be a volatile?

情况的另一个变体是当多个线程处理一个对象X是纯数据,但是通过另一个对象交替执行它们的时间执行(从而永远不会同时访问X) Y依赖并发控制( wait notify synchronize )。对象X的字段是否易变?

Another variant of the situation is when multiple threads manipulate an object X that is plain data, but alternate their temporal execution (so that X is never accessed concurrently) via another object Y that rely on concurrency control (wait, notify, synchronize). Should fields of object X be volatile?

推荐答案

只有当线程之间的发生先于关系建立时,线程的变异才能被其他线程看见。当关系建立时,所有先前的突变变得可见。

Mutations from a thread are guaranteed to become visible to other threads only when an happen-before relationship between the threads is established. When the relationship is established, all previous mutations become visible.

如果另一个对象正确同步对它的访问,则可以安全地使用在孤立采取时未正确同步的对象(请参阅 piggibacking 在Java并发实践中)。

An object that isn't correctly synchronized when taken in isolation can be safe to use if another object correctly synchronizes accesses to it (see piggibacking in Java Concurrency in Practice).

在问题中描述的两种情况下,我认为不需要同步:

In the two cases described in the question, I think no synchronization is needed:


  • Thread.start 建立一个发生于之前的关系,因此来自之前线程的所有突变都是可见的

  • 由对象Y同步,这将建立发生先前的关系,并使更改为X可见(我在博客帖子)。

  • Thread.start establishes a happen-before relationship, so all mutations from previous threads are visible
  • Accesses to object X are synchronized by object Y, which will establish happen-before relationships and make the changes to X visible (I expanded a bit more in a blog post).

如果你知道一个对象X从不被同时访问,那么很可能有一个对象Y间接地同步对X的访问,没关系。唯一不安全的情况,我看到的是如果线程继续时间本身(例如与Thread.sleep或循环,直到一段时间已经消失),以保证互斥:在这种情况下,没有发生先前的关系,建立。

If you know that an object X is never accessed concurrently, chances are there is an object Y that indirectly synchronizes accesses to X, so it's fine. The only unsafe case I see is if threads relay on time itself (e.g. with Thread.sleep or by looping until some time has elasped) to guarantee mutual exclusion: in this case there is no happen-before relationship that is established.

这篇关于同步跨线程共享但未并行访问的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆