【发布时间】:2010-10-01 01:24:30
【问题描述】:
Java 文档说:
不可能两次调用同步方法 交错的同一个对象。
这对静态方法意味着什么?由于静态方法没有关联对象,synchronized关键字会锁定类而不是对象吗?
【问题讨论】:
标签: java class static methods synchronized
Java 文档说:
不可能两次调用同步方法 交错的同一个对象。
这对静态方法意味着什么?由于静态方法没有关联对象,synchronized关键字会锁定类而不是对象吗?
【问题讨论】:
标签: java class static methods synchronized
为了给 Oscar 的回答添加一点细节(非常简洁!),Java 语言规范的相关部分是 8.4.3.6, 'synchronized Methods':
同步方法在执行之前获取一个监视器 (§17.1)。对于类(静态)方法,使用与方法类的 Class 对象关联的监视器。对于实例方法,使用与 this(调用该方法的对象)关联的监视器。
【讨论】:
由于静态方法没有关联对象,同步关键字会锁定类,而不是对象吗?
是的。 :)
【讨论】:
this是在实例方法上获得的锁-,请奥斯卡修复它。
你必须注意的一点(一些程序员通常会陷入这个陷阱)是同步的静态方法和同步的非静态方法之间没有联系,即:
class A {
static synchronized f() {...}
synchronized g() {...}
}
主要:
A a = new A();
线程 1:
A.f();
线程 2:
a.g();
f() 和 g() 彼此不同步,因此可以完全同时执行。
【讨论】:
synchronized (MyClass.class) {...}。
除非你按如下方式实现 g():
g() {
synchronized(getClass()) {
...
}
}
当我想在对象的不同实例之间实现互斥(例如,在访问外部资源时需要)时,我发现这种模式也很有用。
【讨论】:
getClass() 返回 runtime 类型;如果您将类子类化,则父类和子类将在不同的锁上同步。如果您需要确保所有实例使用相同的锁,synchronized(MyClass.class) 是您的最佳选择。
查看Intrinsic Locks and Synchronization上的 oracle 文档页面
您可能想知道调用静态同步方法时会发生什么,因为静态方法与类相关联,而不是与对象相关联。 在这种情况下,线程获取与类关联的 Class 对象的内在锁。 因此,对类的静态字段的访问由不同于任何类实例的锁控制。
【讨论】:
静态方法也有一个关联对象。它属于 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);
}
}
}
所以,现在我们可以有以下场景:
当使用same Object的线程尝试同时访问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文字的单独锁并进入静态同步方法。
【讨论】: