Java教程说:“同一个对象上的两个同步方法的调用不可能交错。”
这对静态方法意味着什么?由于静态方法没有关联对象,所以synchronized关键字会锁定类,而不是对象吗?
答案 0 :(得分:197)
只是为奥斯卡(令人愉悦的简洁!)答案添加一些细节,Java语言规范的相关部分是8.4.3.6, 'synchronized Methods':
synchronized方法在执行之前获取监视器(第17.1节)。对于类(静态)方法,使用与方法类的Class对象关联的监视器。对于实例方法,使用与此关联的监视器(调用该方法的对象)。
答案 1 :(得分:125)
由于静态方法没有关联对象,是否会对类中的synchronized关键字进行锁定而不是对象?
是。 :)
答案 2 :(得分:79)
你需要注意的一点(一些程序员通常属于那个陷阱)是同步静态方法和同步非静态方法之间没有联系,即:
class A {
static synchronized f() {...}
synchronized g() {...}
}
主:
A a = new A();
主题1:
A.f();
主题2:
a.g();
f()和g()彼此不同步,因此可以完全同时执行。
答案 3 :(得分:13)
除非你按如下方式实施g():
g() {
synchronized(getClass()) {
...
}
}
当我想在对象的不同实例之间实现互斥时(例如,在访问外部资源时需要),我发现这种模式也很有用。
答案 4 :(得分:4)
查看Intrinsic Locks and Synchronization
上的oracle文档页面您可能想知道在调用静态同步方法时会发生什么,因为静态方法与类相关联,而不是与对象相关联。 在这种情况下,线程获取与类关联的Class对象的内部锁。 因此,对类的静态字段的访问由与该类的任何实例的锁不同的锁控制。
答案 5 :(得分:2)
静态方法也有一个关联的对象。它属于JDK toolkit中的Class.class文件。当.class文件加载到ram中时,Class.class创建一个名为template object的实例。
例如: - 当您尝试从现有客户类创建对象时,如
Customer c = new Customer();
将Customer.class加载到RAM中。在那一刻,JDK工具箱中的Class.class创建一个名为Template对象的Object,并将Customer.class加载到该模板对象中。该Customer.class的静态成员成为该模板对象中的属性和方法。
因此静态方法或属性也有一个对象
答案 6 :(得分:2)
下面的例子给出了类和对象锁之间的更清晰,希望下面的例子也可以帮助其他人:)
例如,我们在下面的方法中有一个获取类和其他获取对象锁:
public class MultiThread {
public static synchronized void staticLock() throws InterruptedException {
for (int i = 0; i < 10; i++) {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
public synchronized void objLock() throws InterruptedException {
for (int i = 0; i < 10; i++) {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
所以,现在我们可以有以下场景:
当使用相同对象的线程尝试同时访问objLock
OR staticLock
方法时(即两个线程都尝试访问)同样的方法)
Thread-0 0
Thread-0 1
Thread-0 2
Thread-0 3
Thread-0 4
Thread-1 0
Thread-1 1
Thread-1 2
Thread-1 3
Thread-1 4
使用相同对象的线程尝试同时访问staticLock
和objLock
方法时(尝试访问不同的方法)
Thread-0 0
Thread-1 0
Thread-0 1
Thread-1 1
Thread-0 2
Thread-1 2
Thread-1 3
Thread-0 3
Thread-0 4
Thread-1 4
使用不同对象的线程尝试访问staticLock
方法
Thread-0 0
Thread-0 1
Thread-0 2
Thread-0 3
Thread-0 4
Thread-1 0
Thread-1 1
Thread-1 2
Thread-1 3
Thread-1 4
使用不同对象的线程尝试访问objLock
方法
Thread-0 0
Thread-1 0
Thread-0 1
Thread-1 1
Thread-0 2
Thread-1 2
Thread-1 3
Thread-0 3
Thread-0 4
Thread-1 4
答案 7 :(得分:0)
对于那些不熟悉在类对象上锁定的静态同步方法,例如对于字符串类,它的String.class,而实例同步方法锁定在Java中由“this”关键字表示的Object的当前实例。由于这两个对象都不同,因此它们具有不同的锁定,因此当一个线程正在执行静态同步方法时,java中的其他线程不需要等待该线程返回,而是将获取表示为byte .class literal的单独锁定并进入静态同步方法。