在synchronized块中,静态与非静态锁对象的区别

13 浏览
0 Comments

在synchronized块中,静态与非静态锁对象的区别

尝试可视化和理解同步。

1. 使用静态锁对象(代码A)和非静态锁对象(代码B)进行同步块有什么区别?

2. 在实际应用中有何不同?

3. 一个可能会出现的问题而另一个不会有哪些缺陷?

4. 判断使用哪种锁的标准是什么?

代码A:

public class MyClass1 {
  private static final Object lock = new Object();
  public MyClass1() {
    //非同步
    synchronized(lock) {
      //同步
    }
    //非同步
  }
}

代码B:

public class MyClass2 {
  private final Object lock = new Object();
  public MyClass2() {
    //非同步
    synchronized(lock) {
      //同步
    }
    //非同步
  }
}

注意:

上述代码展示了构造函数,但您也可以讨论静态方法和非静态方法的行为差异。当同步块修改静态成员变量时,使用静态锁是否具有优势?

我已经查看了这个问题中的答案,但它并不清楚不同的使用场景是什么。

0
0 Comments

静态锁对象与非静态锁对象的区别很简单:如果锁定的对象在一个静态字段中,那么所有的MyClass实例将会共享该锁(即没有两个对象能够同时锁定该对象)。如果字段是非静态的,则每个实例将有自己的锁,因此只有在相同对象上调用的方法才会相互锁定。

当使用静态锁对象时:

- 线程1调用o1.foo();

- 线程2调用o1.foo(),必须等待线程1完成;

- 线程3调用o2.foo(),同样必须等待线程1(可能还有线程2)完成。

当使用非静态锁对象时:

- 线程1调用o1.foo();

- 线程2调用o1.foo(),必须等待线程1完成;

- 线程3调用o2.foo(),可以继续执行,不需要理会线程1和线程2。

你需要哪种方式取决于你尝试使用同步块来保护的数据类型。一般来说,你希望锁定对象与操作的值具有相同的静态性。如果你只操作非静态值,你将需要一个非静态锁对象。如果你只操作静态值,你将需要一个静态锁对象。

当你操作静态和非静态值时,情况会变得复杂。简单的方法是只使用静态锁对象,但这可能会增加同步块的大小超过必要的程度,并可能导致更多的锁争用。在这些情况下,你可能需要使用静态和非静态锁对象的组合。

在你的特定情况中,你在构造函数中使用锁,该构造函数每个实例只会执行一次,因此在这里使用非静态锁对象没有任何意义。

如果有一组方法通过一个线程操作一个volatile static成员变量,并希望在其他线程访问该成员变量之前完成操作,是否有办法确保这一点?如果需要的话,我可以在Stack Overflow上提出一个单独的问题。

答案:这听起来对我来说是一个单独的问题。简短的答案是:不,你需要同步。只有当volatile的操作是原子的(例如对int类型的单个++运算),并且你不关心顺序(即你不关心在操作之前或之后读取)时,才可以避免同步。

我确实关心读取,它应该在操作之后发生。我想我会将它作为一个单独的问题提出。

实际上,我给你提供了错误的信息:即使是x++在volatile x上也不是原子的。请继续提出一个新的问题来解决此问题。

如果两个线程正在访问同一个对象的两个不同的非静态方法,是否可能同时进行,还是第二个线程必须等待?在一个对象上的锁是否会锁定所有的非静态方法?

'Ghouri'是的,每个线程(访问同一对象资源)都需要等待,直到其他线程释放对任何相同实例的同步方法的锁定。

0