Java教程说:“不可能在同一个对象上对同步方法的两次调用进行交织。”
这对于静态方法意味着什么?由于静态方法没有关联的对象,所以synced关键字会锁定在类上而不是对象上吗?
由于静态方法没有关联的对象,所以同步的关键字将锁定在类上,而不是对象上吗?
是。 :)
只需为Oscar的回答(很简洁!)添加一些细节,Java语言规范的相关部分为8.4.3.6, 'synchronized Methods':
同步方法在执行之前先获取一个监视器(第17.1节)。对于类(静态)方法,使用与该方法的类的Class对象关联的监视器。对于实例方法,使用与此相关联的监视器(为其调用方法的对象)。
您必须要注意的一点(通常是几个程序员都陷入了这个陷阱)是同步的静态方法与同步的非静态方法之间没有链接,即:
class A {
static synchronized f() {...}
synchronized g() {...}
}
主要:
A a = new A();
线程1:
A.f();
线程2:
a.g();
f()和g()彼此不同步,因此可以完全同时执行。
关于对jfpoilpret's answer的以下评论:
但是,如果g()突变了f()正在读取的某个静态变量。我们如何使该线程安全?那我们是否明确获得了该类的锁?
除非您如下实现g()
:
class MyClass {
g() {
synchronized(MyClass.class) {
...
}
}
}
[当我想在对象的不同实例之间实现互斥时(例如,在访问外部资源时需要),我发现此模式也很有用。
在Intrinsic Locks and Synchronization上查看oracle文档页面
您可能想知道当调用静态同步方法时会发生什么,因为静态方法与类而不是对象相关联。 在这种情况下,线程获取与该类关联的Class对象的固有锁定。 因此对类的静态字段的访问由与该类的任何实例的锁都不相同的锁控制。]
静态方法也有一个关联的对象。它属于JDK工具包中的Class.class文件。当.class文件加载到ram中时,Class.class创建它的一个实例,称为模板对象。
下面的示例使类和对象锁定之间的关系更加清晰,希望下面的示例也能对其他人有所帮助:)
对于不熟悉的人,静态同步方法锁定在类对象上,例如对于字符串类,其字符串为String.class,而实例同步方法则锁定Java中由“ this”关键字表示的Object的当前实例。由于这两个对象都不相同,因此它们具有不同的锁,因此当一个线程执行静态同步方法时,java中的其他线程无需等待该线程返回,而是将获取表示为byte .class文字的单独锁,然后输入静态同步方法。