在java中的synchronized方法或块中使用静态成员

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在java中的synchronized方法或块中使用静态成员相关的知识,希望对你有一定的参考价值。

当我在实例方法上使用synchronized方法时,监视器与'this'相关联。另一方面,当我在我的类(静态)方法上进行同步时,监视器与类对象相关联。当我在非静态方法中使用静态变量时会发生什么?会同步吗?

例如,

public class A{

   public static int reg_no = 100;

   public synchronized void registration(){

      A.reg_no = some operation...

   }

}

在上面的例子中,两个或多个线程的静态变量qazxsw poi会发生什么竞争方法qazxsw poi?

答案

使用reg_no注释成员函数时,该方法将在对象的实例上同步。如果要在静态变量上进行同步,则必须手动同步类对象:

registration()

请注意,上面获得了两个锁,如果任何其他代码在另一个顺序中获得相同的两个锁,则可以导致synchronized。您可能希望从方法中删除public synchronized void registration() { synchronized (A.class) { A.reg_no = some operation ... } } ,只留下deadlocks

另一答案

对变量(静态或实例)的访问不同步。该方法的同步将防止单个实例的竞争条件,无论变量(静态或实例)如何

如果你想要防范多个实例,你必须在类文字上进行同步,但这看起来确实是错误的。

另一答案

(经过进一步思考后修改)

对于上面给出的示例,您可以通过声明您的静态int像punkers建议的那样挥发。

但是在一般情况下 - 例如,如果你的静态变量是一个具有可变状态的对象......

synchronized实例方法意味着只允许持有对象实例锁的线程在该类A实例的该方法中进行,并且当该线程在该方法中完成并释放锁时,任何其他线程使用任何其他线程进入任何同步块相同的锁将“看到”您所做的更改。

它不会阻止另一个线程对静态变量进行更改:

  • 直接从外部类A为静态变量赋值(变量是公共的!)
  • 调用类A的静态方法(同步或其他),它重新分配静态变量,因为它将使用不同的锁
  • 调用A类的非同步实例方法

使用synchronized方法通常有点危险 - 它们可能导致死锁,因为锁可以由其他使用您的类/实例作为同步块的目标的代码从外部获取:

synchronized

要么

synchronized (A.class)

更好的方法可能是将静态变量设为私有,添加私有本地变量以用作锁(因此无法在外部锁定),并在方法中的synchronized块中使用私有本地锁:

synchronized (objectOfTypeA) { ... } // takes the instance lock
另一答案

不,您需要将方法与类同步,例如。 synchronized (A.getClass()) { ... } // takes the class lock

另一答案

如果你的问题是与其他线程共享该变量,我会将静态变量声明为volatile,而不是在synchronized方法中添加另一个synchronized块。

以上是关于在java中的synchronized方法或块中使用静态成员的主要内容,如果未能解决你的问题,请参考以下文章

[Java] synchronized在代码块中修饰.class与this的区别

java 同步代码块与同步方法

java类与对象基本使用

深入研究 Java Synchronize 和 Lock 的区别与用法

synchronized(修饰方法和代码块)

synchronized的用法