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

Java 同步静态方法和非静态方法之间的区别,java,synchronization,Java,Synchronization,在java中同步一个静态方法和一个非静态方法有什么区别?有人能用一个例子解释一下吗。同步方法和同步代码块有什么区别吗?简言之,如果在静态方法上同步,则将在类(对象)上同步,而不是在实例(对象)上同步。这意味着在执行静态方法时,整个类都被阻塞。因此,其他静态同步方法也被阻止。Java中的同步基本上是的一种实现。同步非静态方法时,监视器属于实例。在静态方法上同步时,监视器属于该类。同步代码块的想法是相同的,但是监视器属于指定的对象。如果您可以不受影响,那么最好使用同步块,因为它们可以最大限度地减少每

在java中同步一个静态方法和一个非静态方法有什么区别?有人能用一个例子解释一下吗。同步方法和同步代码块有什么区别吗?

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

Java中的同步基本上是的一种实现。同步非静态方法时,监视器属于实例。在静态方法上同步时,监视器属于该类。同步代码块的想法是相同的,但是监视器属于指定的对象。如果您可以不受影响,那么最好使用同步块,因为它们可以最大限度地减少每个线程在

中花费的时间。我将尝试添加一个示例来说明这一点

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

Object a = new Object();
Object b = new Object();
...
synchronized(a){
    doStuff();
}
...
synchronized(b){
    doSomeStuff();
}
...
synchronized(a){
    doOtherStuff();
}
在上面的示例中,运行
doOtherStuff()
的线程将阻止另一个线程进入代码块
doStuff()
。但是,线程可以毫无问题地进入
doSomeStuff()
周围的块,因为该块是在
对象b
上同步的,而不是在
对象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();
)访问该对象是一样的

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

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

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

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

void synchronized m() {...}

void m() { synchronized(this) {...} }
相比之下,静态同步方法与以下方法相同:

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

伙计,只是一个提示。与您的问题无关:

如果有do*Stuff()方法

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


那你就完蛋了。因为锁在值内,而不是在引用内。请参见

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

来自javadoc

调用静态同步方法时,因为静态方法与类而不是对象相关联。在这种情况下,线程获取与类关联的类对象的内在锁。因此,对类的静态字段的访问由一个锁控制,该锁不同于类的任何实例的锁

public static synchronized void getInstance(){}
当我们获取任何类的锁时,我们实际上获取了“类”类实例的锁,该类实例对于类的所有实例都是唯一的

public synchronized void getInstance(){}

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

。。。如果它们也是同步的。只是稍微改进一下:对于静态方法,监视器属于
实例,而不是“类”。顺便说一句-如果您必须使用多个类加载器,并且多个类加载器实际加载同一个类,那么这一点非常重要-那么对于同一个类,我们有多个
class
实例…@Andreas\D感谢您的澄清。我没有意识到多类加载器之间的细微差别。
public synchronized void getInstance(){}