【问题标题】:Java sychronized block while access to the class A field in class BJava同步块同时访问B类中的A类字段
【发布时间】:2018-12-29 14:43:08
【问题描述】:

我想问一个与Java同步相关的问题,为了澄清我的疑惑,我写了如下简单的代码:

class A {
 public int variable;
 public int secondVariable;
 public Object variableLock = new Object();
 public Object secondVariableLock = new Object();

 public void doingSthWithVariable() {
  synchronized (variableLock) {
  .... } } 

 public void doingSthWithVariableInOtherMethod() {
  synchronized (variableLock) {
  .... } }

 public void doingSthWithSecondVariable() {
  synchronized (secondVariableLock) {
  .... } }

 public void doingSthWithSecondVariableInOtherMethod() {
  synchronized (secondVariableLock) {
  .... } }

}

class B {
 public A instanceOfA;

 public void doingSthWithAVariables() {
  synchronized (instanceofA.variableLock) {
    synchronized (instanceofA.secondVariableLock) {
      ....} } }
 }

我的问题是:如果它是安全的,并且在 B 类中使用 A 类的 variableLock/secondVariableLock 是否是一种好习惯? 我的意思是,我需要在 B 类的实例中阻止这两个变量的任何更改,我想知道这是否是一个好方法。 还有一个问题:如果我在多个 B 对象中有相同的 instanceOfA 怎么办?

在我看来答案是肯定的(这不是不安全的),但我只是想确保并询问更好的方法。

【问题讨论】:

  • 使用公共可变锁绝对不是一个好主意。我不确定您想要实现什么,但封装是使事情安全的关键。如果您希望在具有变量和第二个变量的互斥锁中执行方法,请将其放在 A 类中。将您的锁设为私有且最终。
  • 那么如何将锁设为私有并由 A 类的公共 getter 将它们放入 B 类?
  • 这稍微好一点,但它仍然是灾难的好方法。例如,两个锁同步但顺序不同的两个线程将导致死锁。你想解决什么具体的问题?
  • 为什么需要两把锁?您只需要一把锁即可保护您的产品收藏。
  • 回到我的第一条评论。如果你真的想要单独的锁,那么封装不要让每个调用者负责正确的锁定。把它放在一个类中。

标签: java synchronization synchronized


【解决方案1】:

整个结构应该重新设计。

一个类应该尽可能多地封装它的内部。在一个理想的世界中,没有其他类应该看到这些字段或者必须知道什么时候同步/锁定什么。一个类应该公开有意义的方法来回答有关此实例的问题或将此实例的状态从一种有效状态修改为另一种有效状态。

“有效状态”的概念取决于域,但通常涉及字段值的组合,例如(简化的)马路交叉口不应让所有四个交通灯都变绿。如果这种情况暂时出现在状态改变方法内部,它一定不能被外界看到。

使用synchronized 关键字是实现这一目标的一种(传统)方法。您将声明 synchronized 状态更改器以及可能受无效状态影响的所有方法。

如果状态分解为多个独立的部分,您只需为单个实例设置多个锁对象,这些部分可以更改而不会相互影响。但是,如果字段组如此松散耦合,您为什么将其建模为一个大实例而不是一堆较小的实例?

还有一点:如果您允许其他类修改对实例有效性至关重要的字段,您将完全破坏任何封装。然后你不再做面向对象的编程,而是像 1970 年代和 1980 年代的 PASCAL 那样将实例视为结构。

查看 Java 库中的线程安全类,例如java.util.Vector。这个类遵循简单的模式,一次只允许一个线程访问关键代码,只需声明一些基本方法synchronized,即使用实例本身作为锁对象。

【讨论】:

    【解决方案2】:

    更常见的方法是实例化一个 ReadWriteLock 并从中生成两个写锁,并在 A 和 B 中使用它们。A 的同一个实例将共享相同的锁

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-20
      • 1970-01-01
      • 2014-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多