如何跨类使用synchronized块?

use*_*164 14 java multithreading synchronizing

我想知道如何跨类使用synchronized块.我的意思是,我想在多个类中同步块,但它们都在同一个对象上进行同步.我想到如何做到这一点的唯一方法是这样的:

//class 1
public static Object obj = new Object();

someMethod(){
     synchronized(obj){
         //code
     }
}


//class 2
someMethod(){
     synchronized(firstClass.obj){
         //code
     }
}
Run Code Online (Sandbox Code Playgroud)

在这个例子中,我创建了一个在第一个类中同步的任意Object,在第二个类中也通过静态引用它来同步它.但是,这对我来说似乎很糟糕.有没有更好的方法来实现这一目标?

Nat*_*hes 9

具有用作锁的静态对象通常是不可取的,因为整个应用程序中一次只有一个线程可以取得进展.如果你有多个类共享相同的锁,甚至更糟,你可以得到一个几乎没有实际并发性的程序.

Java在每个对象上具有内部锁定的原因是对象可以使用同步来保护自己的数据.线程调用对象上的方法,如果需要保护对象不受并发更改的影响,则可以将synchronized关键字添加到对象的方法中,以便每个调用线程必须先获取该对象的锁定,然后才能对其执行方法.这种方式调用不相关的对象不需要相同的锁,你有更好的机会让代码实际并发运行.

锁定不一定是您的第一个并发技术.实际上,您可以使用许多技术.按降序排列顺序:

1)尽可能消除可变状态; 不可变对象和无状态函数是理想的,因为没有要保护的状态,也不需要锁定.

2)尽可能使用线程限制; 如果您可以将状态限制为单个线程,则可以避免数据争用和内存可见性问题,并最大限度地减少锁定量.

3)使用并发库和框架优先使用锁定来滚动自己的对象.熟悉java.util.concurrent中的类.与应用程序开发人员可以管理的任何内容相比,它们编写得更好.

一旦你完成了上面的1,2和3的尽可能多的工作,那么你可以考虑使用锁定(其中锁定包括ReentrantLock和内部锁定等选项).将锁与受保护对象相关联可以最大限度地减小锁的范围,从而使线程不会长时间保持锁定.

此外,如果锁不在数据被锁定的情况下,那么如果在某些时候你决定使用不同的锁而不是让所有东西锁定在同一个东西上,那么避免死锁可能具有挑战性.锁定需要保护的数据结构使锁定行为更容易推理.

完全避免内在锁定的建议可能是过早优化.首先要确保你锁定正确的东西不超过必要的.


Gau*_*wal 5

选项1:

更简单的方法是使用枚举或静态内部类创建单独的对象(单例).然后使用它锁定两个类,它看起来很优雅:

// use any singleton object, at it's simplest can use any unique string in double quotes
  public enum LockObj {
    INSTANCE;
  }

  public class Class1 {
    public void someMethod() {
      synchronized (LockObj.INSTANCE) {
        // some code
      }
    }
  }

  public class Class2 {
    public void someMethod() {
      synchronized (LockObj.INSTANCE) {
        // some code
      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

OPTION:2

您可以使用任何字符串,因为JVM确保每个JVM只出现一次.唯一性是确保此字符串上没有其他锁定.根本不要使用此选项,这只是为了澄清这个概念.

     public class Class1 {
    public void someMethod() {
      synchronized ("MyUniqueString") {
        // some code
      }
    }
  }

   public class Class2 {
        public void someMethod() {
          synchronized ("MyUniqueString") {
            // some code
          }
        }
      }
Run Code Online (Sandbox Code Playgroud)

  • 锁定一个字符串文字让我觉得很可怕.据我所知,跨类的字符串常量的重复数据删除是一个实现细节,而不是可移植的.并且总是存在其他开发人员碰巧在_same_字符串文字上同步的风险,这可能导致死锁或其他不良行为. (3认同)

Zar*_*tra 3

你的代码对我来说似乎是有效的,即使它看起来不太好。但请将您正在同步的对象设置为final。但是,根据您的实际情况,可能需要考虑一些因素。

无论如何,都应该在 Javadocs 中清楚地说明您想要归档的内容。

另一种方法是同步,FirstClass例如

synchronized (FirstClass.class) {
// do what you have to do
} 
Run Code Online (Sandbox Code Playgroud)

然而,每个synchronized方法都FirstClass与上面的同步块相同。换句话说,它们也是synchronized在同一个物体上。- 根据上下文,可能会更好。

BlockingQueue在其他情况下,如果您想要同步数据库访问或类似的情况,也许您更喜欢某种实现。