这个问题以前可能已经回答过了,但是由于这个问题的复杂性,我需要一个确认。所以我重新措辞这个问题
问题1:当一个线程进入一个同步块时,内存屏障将包括被触摸的任何字段,而不仅仅是我同步的对象的字段?因此,如果在一个同步块中修改了许多对象,那么在线程内存缓存之间会有大量内存移动。
Thread 1
object.field1 = "";
synchronized (lock) {
farAwayObject.field1 = "";
farAwayObject.evenFarther.field2 = "";
}
Thread 2. assuming thread ordering is correct
synchronized (lock) {
//thread 2 guaranteed to see all fields above as ""
//even object.field1 ?
}
问题 2 : object.field1 = “”;
在线程 1 中隐式地是“发生前”关系的一部分?
我希望是这样,但可能不是这样。如果没有,有没有一个技巧可以让它这样做,而不将其放入同步块?否则很难对程序进行推理,并且将所有内容都放在同步{}下是不切实际的。
编辑:澄清:object.field1不是易失性的,问题是“线程2是否保证看到线程1的写入,至少”。我的问题是关于内存可见性的。为了这个参数,假设只有线程 1 写入非易失性 object.field1。
问题2可以改写为
“锁上的同步块是否会推动之前所做的更改,以便被在同一锁上同步的其他线程看到?
内存屏障将包括所触及的任何字段,而不仅仅是我同步的对象的字段?
是的。
Is object.field1 =在线程1中隐含部分发生前关系?
是的,即使它没有挥发性。
发生在顺序之前的是偏序。
先发生顺序是由同步的传递闭包给出的,带有边和程序顺序。它必须是一个有效的部分顺序:自反、传递和反对称。
(JLS 17.4.7)
同步边缘之前的操作(即同步锁的释放)按程序顺序排序,因此与释放同步。传递性说,由另一个线程中相同锁的获取排序的操作因此具有发生之前的顺序,即释放该锁和释放该锁之前的操作,无论它是否在同步
块的主体内。要记住的重要一点是,排序发生在操作(即获取/释放锁)上,而不是像同步关键字的括号所暗示的块。括号表示获取/释放操作的位置以及一组操作无法交错的位置。
最后,请记住“之前发生”是一个“部分”顺序。它的意思是:
当线程进入同步块时,内存屏障将包括任何接触的字段,而不仅仅是我同步的对象的字段
假设farAwayObject
和evenFarther
的字段始终通过在您的应用程序周围的同一对象上获取lock
来修改和访问,所有线程将始终看到对farAwayObject
和evenFarther
所做的更新,因为同步
强制执行发生前条件。
//线程2保证将上面的所有字段视为“”
对于 object.field1
来说,在不知道它是如何声明的的情况下,不能这么说。假设 field1
是未标记为易失性的
引用,则在关系和线程可能会看到它的过时值之前,它不会是发生的一部分。
我希望是,但可能不是。如果不是,有没有一个技巧可以让它不进入同步块?
是的。将 object.field1
标记为易失性
。
添加您的编辑:
问题2可以改写为
“锁上的同步块是否会推动之前所做的更改,以便被在同一锁上同步的其他线程看到?
AFAIK答案是是,前提是写入线程在读取线程之前获得锁。不幸的是,这通常是您无法保证的,这就是为什么object.field1
需要标记为易失性
或语句需要移动到同步
块内。
看看 JSR 133,它讨论了当线程退出同步块
时,缓存被刷新到主内存。这应该进一步澄清一些事情。
1) 当一个线程进入一个同步块时,内存屏障将包括任何被触摸的字段,而不仅仅是我同步的对象的字段?
正确。(假设线程1和线程2在同一个锁上同步。)
因此,如果在同步块内修改了许多许多对象,则线程内存缓存之间的大量内存移动。
可能是的。但是,它(可能)不是在缓存之间移动。更有可能的是,它是从一个处理器的缓存移动到内存,以及从内存到第二个处理器的缓存的移动。当然,这取决于硬件如何实现内存层次结构。
2)Is object . field 1 = " ";在线程1中隐含部分发生前关系?
这是一连串发生之前的关系
object.field1
的写入发生在获取锁之前。farAwayObject
等等之前。object.field1
之前。问题是,如果在线程1或其他线程获取< code>lock之前,存在对< code>object.field1的干预写入,会发生什么情况。在这两种情况下,发生之前链都不足以确保线程2看到线程1写入的值。
本文向大家介绍Java中的同步关键字,包括了Java中的同步关键字的使用技巧和注意事项,需要的朋友参考一下 当我们在程序中启动两个或多个线程时,可能会出现多个线程尝试访问同一资源,最终由于并发问题,它们可能产生无法预料的结果的情况。例如,如果多个线程试图在同一文件中写入数据,则它们可能会破坏数据,因为其中一个线程可以覆盖数据,或者一个线程同时打开同一文件时,另一个线程可能正在关闭同一文件。 因此,
问题内容: c#是否具有自己的java“ synchronized”关键字版本? 即在Java中,可以将其指定为函数,对象或代码块,如下所示: 要么 问题答案: 首先-大多数类将永远不需要是线程安全的。使用YAGNI:仅当你知道实际上将要使用它(并对其进行测试)时,才应用线程安全性。 对于方法级的东西,有: 这也可以用于访问器(属性和事件): 请注意,默认情况下,类似字段的事件是同步的,而自动实现
问题内容: 所以我正在用关键字测试。这是我尝试的示例: 当我运行它时,来自两个线程的调用方法的输出生成以下输出: 当我将方法更改为: 我得到以下输出: 尽管这使我清楚地了解的目的,但我想知道还有其他可以使用的原因。还是我在这里所做的,是为什么我们需要使用此关键字的唯一原因? 谢谢。 编辑: 令我感到困惑的另一件事是,在第一个输出中,为什么计数器在7之后变为3。这对我来说似乎有点不可能,但是每次尝试
问题内容: 假设我有以下Java代码 同步是否会阻止重新排序?a,b和c之间没有依赖关系。先分配给b然后再分配给c?如果我还没有同步,则可以用JVM选择的任何方式对语句重新排序? 问题答案: 同步是否会阻止重新排序? 它可以防止重新排序。您仍然可以在同步块外部和同步块内部进行重新排序,但不能从同步块内部对其进行重新排序。 a,b和c之间没有依赖关系。 没关系。 先分配给b然后再分配给c? 是。但是
问题内容: C#中 var 关键字的一种用法是隐式类型声明。 var 的Java等效语法是什么? 问题答案: 空无一人。las,您必须输入完整的类型名称。 编辑:发布7年后,Java 10中添加了局部变量的类型推断(带有)。 编辑:发布6年后,从下面收集一些评论: C#使用关键字的原因是因为在.NET中可能有没有名称的Types。例如: 在这种情况下,不可能给赋予正确的类型。6年前,这在Java中
本文向大家介绍Java中synchronized关键字修饰方法同步的用法详解,包括了Java中synchronized关键字修饰方法同步的用法详解的使用技巧和注意事项,需要的朋友参考一下 Java的最基本的同步方式,即使用synchronized关键字来控制一个方法的并发访问。 每一个用synchronized关键字声明的方法都是临界区。在Java中,同一个对象的临界区,在同一时间只有一个允许被访