【问题标题】:Java combine explicit locks with synchronized methodsJava 将显式锁与同步方法相结合
【发布时间】:2015-06-12 08:23:17
【问题描述】:

我有一个线程安全的类容器:

public class Container {
  private int x;
  ...
  public synchronized int getX();
  public synchronized void setX(int x);
}

然后我有一个容器列表:

List<Container> containers;

我想遍历列表,在每次迭代时获取容器的锁,并且仅在循环结束时释放所有锁。 像这样的:

for(Container c : containers) {
  c.lock();
  //do stuff
}
for(Container c : containers)
  c.unlock();

我仍然希望其他线程能够继续使用解锁容器的 getX 和 setX 方法,但出于各种原因,我不希望对已经分析过的容器允许这样做。

你知道它的 java 代码吗?

更好的想法也值得赞赏。

【问题讨论】:

  • lock()unlock()getXsetX 中的第一个和最后一个怎么样?
  • @aioobe:我想将同步方法与显式锁结合起来(希望它是可能的,但我认为这是因为在幕后同步关键字获取对象锁)。
  • @Lance Java:但在我的情况下,您将如何在 for 循环中使用 try-finally?也许尝试所有的 for 循环并最终释放所有的锁?解锁解锁的锁可以吗?
  • 关于不同的方法:如果你解释一下你用 Container 做什么,也许用不可变容器的解决方案会更好......

标签: java multithreading concurrency synchronization locking


【解决方案1】:

恐怕这是不可能的。 Java 语言对synchronized (...) { ... } 块(和同步方法)施加了严格的嵌套原则。

话虽如此,还是有一些讨厌的解决方法。在 字节码 中,同步块转换为两个单独的 monitorenter / monitorexit 指令。使用sun.mis.Unsafe.monitorEnter()monitorExit() 也可以实现同样的效果。

但是,在这种情况下,我强烈建议您重新考虑设计。我建议你让getXsetX 获取/释放一个内部Lock(遍历方法也使用它)。特别是,您可以将ReadWriteLock 用于您的setXgetX 方法。事实上,由于其他原因,这种方法也比使用synchronized 方法要好。例如:

Why is it a good practice to have separate locks instead of having lock on object that get modified in the synchronized block in java?

【讨论】:

  • synchronized关键字不获取对象本身的锁吗?这就像在方法中编写 synchronized(this){} 一样。如果我们锁定 this,为什么我们不能创建一个锁定对象(this)的锁?
  • 有了内部锁,我不会有同样的问题吗?如何在不使用 synchronized 关键字的情况下获取多个内部锁(每次迭代一个)?
  • 你的理解是正确的。我们不能只做lock(this); 和之后的unlock(this); 之类的事情的唯一原因(这将对应于左大括号{ 和右大括号}of synchronized (this))是获取的唯一方法这种类型的锁是通过 synchronized 关键字(除非您使用我在回答中提到的不安全操作),并且 synchronized 关键字具有 { ... } 块的语法约束。
  • 不,使用内部锁,您可以使用Lock,它具有单独的lock()unlock() 方法! (答案已更新。)
  • 谢谢,但是如何在 for 循环中编写 try-finally 块?我的意思是最后我应该解锁所有的锁吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-13
  • 1970-01-01
  • 2017-04-28
  • 1970-01-01
  • 2011-03-04
相关资源
最近更新 更多