同步静态方法和非静态方法之间的区别

时间:2011-06-16 06:22:25

标签: java synchronization

在java中同步静态方法和非静态方法有什么区别?任何人都可以用一个例子来解释。同步方法和同步代码块有什么不同吗?

7 个答案:

答案 0 :(得分:73)

我会尝试添加一个示例,使其更加清晰。

如前所述,Java中的synchronized是Monitor概念的实现。将代码块标记为已同步时,请使用对象作为参数。当一个执行线程进入这样一个代码块时,它必须先等待,直到该同一个对象的同步块中没有其他正在执行的线程。

Object a = new Object();
Object b = new Object();
...
synchronized(a){
    doStuff();
}
...
synchronized(b){
    doSomeStuff();
}
...
synchronized(a){
    doOtherStuff();
}

在上面的示例中,运行doOtherStuff()的线程会阻止另一个线程进入保护doStuff()的代码块。但是,一个帖子可以在doSomeStuff()周围进入该区块而不会出现问题,因为该问题已在Object b上同步,而不是Object a

在实例方法(非静态方法)上使用synchronized修饰符时,它与具有“this”作为参数的synchronized块非常相似。因此,在以下示例中,methodA()methodB()的行为方式相同:

public synchronized void methodA() {
  doStuff();
}
...
public void methodB() {
    synchronized(this) {
        doStuff();
    }
}

请注意,如果该类中的methodC()未同步且没有同步块,则不会阻止某个线程进入该方法,粗心的编程可能会让该线程访问不安全的代码在对象中。

如果你有一个带有synchronized修饰符的静态方法,它实际上与使用ClassName.class作为参数的同步块一样(如果你有一个类的对象,ClassName cn = new ClassName();,您可以使用Class c = cn.getClass();

访问该对象
class ClassName {
  public void static synchronized staticMethodA() {
    doStaticStuff();
  }
  public static void staticMethodB() {
    synchronized(ClassName.class) {
      doStaticStuff();
    }
  }
  public void nonStaticMethodC() {
    synchronized(this.getClass()) {
      doStuff();
    }
  }
  public static void unSafeStaticMethodD() {
   doStaticStuff();
  }
}

因此,在上面的示例中,staticMethodA()staticMethodB()的行为方式相同。当正在同一对象上同步时,执行线程也将被阻止访问nonStaticMethodC()中的代码块。

但是,重要的是要知道没有任何东西会阻止正在执行的线程访问unSafeStaticMethodD()。即使我们说静态方法“在Class对象上同步”,也不意味着它同步对该类中方法的所有访问。它只是意味着它使用Class对象进行同步。仍然可以进行非安全访问。

答案 1 :(得分:19)

简而言之,如果您在静态方法上进行同步,则将在类(对象)上进行同步,而不是在实例(对象)上进行同步。这意味着在执行静态方法时,整个类都被阻止。所以其他静态同步方法也被阻止了。

答案 2 :(得分:4)

Java中的同步基本上是monitors的实现。同步非静态方法时,监视器属于实例。在静态方法上同步时,监视器属于该类。同步代码块是一样的想法,但监视器属于指定的对象。如果你可以逃脱它,最好使用synchronized块,因为它们可以最小化每个线程在critical section中花费的时间

答案 3 :(得分:3)

同步块和同步方法之间几乎没有区别。基本上是:

void synchronized m() {...}

相同
void m() { synchronized(this) {...} }

通过比较,静态同步方法与:

相同
static void m() { synchronized(MyClass.class) {...} }

答案 4 :(得分:0)

老兄,只是一个暗示。与您的问题无关:

如果有任何do * Stuff()方法

this.a= /*yet another*/ new Object();

this.b= /*yet another*/ new Object();
然后你被搞砸了。因为锁在值内,而不在引用内。见Java synchronized references

答案 5 :(得分:0)

Java Thread在进入 synchronized java方法实例时获取对象级别锁定并获取 进入静态同步java方法时的类级别锁定。 通过使用 synchronized块,您只能锁定代码的关键部分,并避免锁定可能降低性能的整个方法。

答案 6 :(得分:0)

来自javadoc https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

当调用静态同步方法时,因为静态方法与类而不是对象相关联。在这种情况下,线程获取与该类关联的Class对象的固有锁定。因此,通过与该类的任何实例的锁不同的锁来控制对类的静态字段的访问。

public static synchronized void getInstance(){}

当我们获得任何类的锁时,实际上是获得了“ Class”类实例的锁,该锁仅对所有类实例都是一个。

public synchronized void getInstance(){}

我们可以创建一个类的多个对象,并且每个对象都有一个与之关联的锁。