首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java内存模型:重新排序和并发锁

Java内存模型:重新排序和并发锁
EN

Stack Overflow用户
提问于 2010-04-05 00:36:43
回答 4查看 3.9K关注 0票数 8

java meomry模型要求在同一监视器上同步的synchronize块对在这些块中修改的变量执行预实现。示例:

代码语言:javascript
复制
// in thread A
synchronized( lock )
{
  x = true;
}

// in thread B
synchronized( lock )
{
  System.out.println( x );
}

在这种情况下,只要线程A已经传递了x==true -block,线程B就会看到该线程。现在,我正在重写大量代码,以便在java.util.concurrent中使用更灵活(据说更快)的锁,特别是ReentrantReadWriteLock。这个例子如下所示:

编辑:示例失败了,因为我错误地转换了代码,正如matt b所指出的。

代码语言:javascript
复制
// in thread A
lock.writeLock().lock();
{
  x = true;
}
lock.writeLock().unlock();

// in thread B
lock.readLock().lock();
{
  System.out.println( x );
}
lock.readLock().unlock();

但是,我还没有在内存模型规范中看到任何提示,表明这样的锁也意味着必要的排序。从实现的角度来看,它似乎依赖于对AbstractQueuedSynchronizer内部易失性变量的访问(至少对于sun实现来说是这样)。然而,这并不是任何规范的一部分,而且对非易失性变量的访问也没有被这些变量的内存屏障所覆盖,是吗?

下面是我的问题:

  • 假设与“旧”synchronized块相同的顺序安全吗?
  • 这在什么地方有记录吗?
  • 访问任何易失性变量是否是任何其他变量的内存屏障?

你好,斯特芬

--

对Yanamon的评论:

请查看以下代码:

代码语言:javascript
复制
// in thread a
x = 1;
synchronized ( a ) { y = 2; }
z = 3;

// in thread b
System.out.println( x );
synchronized ( a ) { System.out.println( y ); }
System.out.println( z );

据我所知,内存屏障强制第二个输出显示2,但对其他变量没有保证影响.?那么,这如何与访问易失变量相比较呢?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-04-05 00:43:53

来自API-doc

所有锁实现都必须强制执行内置监视器锁提供的相同的内存同步语义,如Java语言规范第三版(17.4内存模型)所述: *成功的锁操作与成功的锁定操作具有相同的内存同步效果。*成功的解锁操作与成功的解锁操作具有相同的内存同步效果。 不成功的锁定和解锁操作以及重入锁定/解锁操作不需要任何内存同步效果。

票数 5
EN

Stack Overflow用户

发布于 2010-04-05 01:10:09

除了内存模型的语义保证的问题之外,我认为您正在发布的代码存在一些问题。

  1. 在同一个锁上同步两次--这是不必要的。在使用Lock实现时,不需要使用synchronized块。
  2. 使用Lock的标准成语是在try-finally块中这样做,以防止意外解锁(因为在进入任何块时,锁不会自动释放,就像synchronized块一样)。

您应该使用类似于以下内容的Lock

代码语言:javascript
复制
lock.lock();
try {
    //do stuff
}
finally { 
    lock.unlock();
}
票数 4
EN

Stack Overflow用户

发布于 2010-04-05 01:11:53

现在,读取和写入易失性变量在操作排序之前和之后执行。写入易失性变量与释放监视器具有相同的效果,读取变量的效果与获取监视器的效果相同。下面的示例使它更加清晰:

代码语言:javascript
复制
volatile boolean memoryBarrier = false;
int unguardedValue = 0;

//thread a:
unguardedValue = 10;
memoryBarrier = true;

// thread b
if (memoryBarrier) {
  // unguardedValue is guaranteed to be read as 10;
}

但是,尽管如此,您提供的示例代码看起来并没有真正使用ReentrantLock,因为它是为使用而设计的。

  1. 围绕着Lock的使用,加上syncronized的内置关键字,可以有效地访问已经是单线程的锁,这样Lock就没有机会做任何真正的工作。
  2. 获取一个发布Lock应该按照下面的模式进行,这在Lock的java文档中得到了概述
代码语言:javascript
复制
lock.readLock().lock();
try {
  // Do work
} finally {
  lock.readLock.unlock();
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2576443

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档