Java 文档说:
同一对象上的同步方法的两次调用不可能交错。
这对静态方法意味着什么?由于静态方法没有关联对象,同步关键字会锁定类而不是对象吗?
Java 文档说:
同一对象上的同步方法的两次调用不可能交错。
这对静态方法意味着什么?由于静态方法没有关联对象,同步关键字会锁定类而不是对象吗?
只是为了给 Oscar 的答案(非常简洁!)添加一点细节,Java 语言规范的相关部分是8.4.3.6, 'synchronized Methods':
同步方法在执行之前获取监视器(第 17.1 节)。对于类(静态)方法,使用与方法类的 Class 对象关联的监视器。对于实例方法,使用与 this(调用该方法的对象)关联的监视器。
由于静态方法没有关联对象, 同步关键字会锁定类而不是对象吗?
是的。:)
您必须注意的一点(一些程序员通常落入那个陷阱)是同步的静态方法和同步的非静态方法之间没有联系,即:
class A {
static synchronized f() {...}
synchronized g() {...}
}
主要的:
A a = new A();
线程 1:
A.f();
线程 2:
a.g();
f() 和 g() 彼此不同步,因此可以完全同时执行。
除非您按如下方式实现 g():
g() {
synchronized(getClass()) {
...
}
}
当我想在对象的不同实例之间实现互斥(例如,在访问外部资源时需要)时,我发现这种模式也很有用。
查看有关 内在锁和同步的 oracle 文档页面
您可能想知道调用静态同步方法时会发生什么,因为静态方法与类相关联,而不是与对象相关联。在这种情况下,线程获取与类关联的类对象的内在锁。因此,对类的静态字段的访问由不同于任何类实例的锁的锁控制。
静态方法也有关联的对象。它属于 JDK 工具包中的 Class.class 文件。当 .class 文件加载到 ram 中时,Class.class 会创建它的一个实例,称为模板对象。
例如:-当您尝试从现有客户类创建对象时,例如
Customer c = new Customer();
Customer.class 加载到 RAM 中。在那一刻,JDK 工具包中的 Class.class 创建了一个名为 Template 对象的对象,并将该 Customer.class 加载到该模板对象中。该 Customer.class 的静态成员成为该模板对象中的属性和方法。
所以静态方法或属性也有对象
下面的例子更清楚地说明了类和对象锁,希望下面的例子也能帮助其他人:)
例如,我们有以下方法,一个是获取类,另一个是获取对象锁:
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
对于那些不熟悉锁定在类对象上的静态同步方法的人,例如对于字符串类它的 String.class,而实例同步方法锁定在 Java 中的“this”关键字表示的 Object 的当前实例上。由于这两个对象不同,它们具有不同的锁,因此当一个线程正在执行静态同步方法时,java中的其他线程不需要等待该线程返回,而是将获取表示为字节.class文字的单独锁并进入静态同步方法。