Java 在访问 class B 中的 class A 字段时同步块
Java sychronized block while access to the class A field in class B
我想问 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) {
....} } }
}
我的问题是:在 class B 中使用 class A 中的 variableLock/secondVariableLock 是否安全并且是一种好的做法?
我的意思是,我需要在 class B 的实例中阻止这两个变量的任何更改,我想知道这是否是一个好方法。
还有一个问题:如果我在多个 B 对象中有相同的 instanceOfA 怎么办?
在我看来答案是肯定的(这不是不安全的),但我只是想确保并询问更好的方法。
一种更常见的方法是实例化一个 ReadWriteLock 并从中生成两个写锁,并在 A 和 B 中使用它们。A 的同一个实例将共享相同的锁
整个结构应该重新设计。
A class 应该尽可能多地封装它的内部结构。在一个理想的世界中,没有其他人 class 应该看到这些字段或必须知道什么时候 synchronize/lock。 class 应该公开有意义的方法来回答有关此实例的问题或将此实例的状态从一种有效状态修改为另一种有效状态。
"valid state" 的概念与域相关,但通常涉及字段值的组合,例如一个(简化的)街道交叉口不应该有所有四个交通灯都是绿色的。如果这种情况在状态改变方法内部暂时出现,它一定不能被外界看到。
并且使用 synchronized
关键字是一种(传统的)实现方式。您将声明 synchronized
状态转换器以及可能受无效状态影响的所有方法。
如果状态分解为多个独立的部分,可以在不影响彼此的情况下更改这些部分,那么您只需要为单个实例使用多个锁对象。但是,如果字段组如此松散耦合,您为什么将其建模为一个大实例而不是一堆较小的实例?
还有一点:如果您允许其他 class 修改对实例有效性至关重要的字段,您将完全破坏任何封装。那么你不再进行面向对象编程,而是像 1970 年代和 80 年代的 PASCAL 那样将实例视为结构。
查看 Java 库中的线程安全 classes,例如java.util.Vector
。 class 遵循简单的模式,一次只允许一个线程访问关键代码,只需声明一些基本方法 synchronized
,即使用实例本身作为锁定对象。
我想问 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) {
....} } }
}
我的问题是:在 class B 中使用 class A 中的 variableLock/secondVariableLock 是否安全并且是一种好的做法? 我的意思是,我需要在 class B 的实例中阻止这两个变量的任何更改,我想知道这是否是一个好方法。 还有一个问题:如果我在多个 B 对象中有相同的 instanceOfA 怎么办?
在我看来答案是肯定的(这不是不安全的),但我只是想确保并询问更好的方法。
一种更常见的方法是实例化一个 ReadWriteLock 并从中生成两个写锁,并在 A 和 B 中使用它们。A 的同一个实例将共享相同的锁
整个结构应该重新设计。
A class 应该尽可能多地封装它的内部结构。在一个理想的世界中,没有其他人 class 应该看到这些字段或必须知道什么时候 synchronize/lock。 class 应该公开有意义的方法来回答有关此实例的问题或将此实例的状态从一种有效状态修改为另一种有效状态。
"valid state" 的概念与域相关,但通常涉及字段值的组合,例如一个(简化的)街道交叉口不应该有所有四个交通灯都是绿色的。如果这种情况在状态改变方法内部暂时出现,它一定不能被外界看到。
并且使用 synchronized
关键字是一种(传统的)实现方式。您将声明 synchronized
状态转换器以及可能受无效状态影响的所有方法。
如果状态分解为多个独立的部分,可以在不影响彼此的情况下更改这些部分,那么您只需要为单个实例使用多个锁对象。但是,如果字段组如此松散耦合,您为什么将其建模为一个大实例而不是一堆较小的实例?
还有一点:如果您允许其他 class 修改对实例有效性至关重要的字段,您将完全破坏任何封装。那么你不再进行面向对象编程,而是像 1970 年代和 80 年代的 PASCAL 那样将实例视为结构。
查看 Java 库中的线程安全 classes,例如java.util.Vector
。 class 遵循简单的模式,一次只允许一个线程访问关键代码,只需声明一些基本方法 synchronized
,即使用实例本身作为锁定对象。