在java中同步静态方法和非静态方法有什么区别?任何人都可以用一个例子来解释。同步方法和同步代码块有什么不同吗?
答案 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(){}
我们可以创建一个类的多个对象,并且每个对象都有一个与之关联的锁。