我是否同步在同一个对象实例在下面的代码? 我能做到安全?
Class Sync {}
Class A implements Runnable {
void run() {
synchronized(Sync.class) {
System.out.println("I am synchronized");
}
}
}
Class B implements Runnable {
void run() {
synchronized(Sync.class) {
System.out.println("I too am synchronized");
}
}
}
你必须做的加载之间的区别Class
和解析 Class
。
文字类和特殊方法Class.forName(…)
比的方法不同ClassLoader.loadClass(…)
虽然ClassLoader
有可能实现以奇怪的方式,例如通过在每个调用返回不同的情况下后者,JVM将解决每个班级每个上下文一次,以及记住结果。
重要的一点是, 如果一个符号引用的决议可以被重定向,一个static final
变量将没有帮助。 如果你有相同的两个实例Class
在JVM中,两个不同版本的的static final
字段会存在的。
有一个接一个一个之间的映射Class
实例和每个类数据的JVM。
举出几个官员的话:
JVMSpec§5.3.2。 载入使用用户定义的类装载器
...首先,Java虚拟机确定是否L具有已被记录为N.表示如果是这样的类或接口的初始化加载器,这个类或接口是C,且无类的创建是必要的。 ...
...
JVMSpec§5.3.5。 从一个类文件表示派生一个类
下面的步骤被用于导出一类对象使用装载机L从在类文件格式声称的表示由N个表示的非数组类或接口℃。
(1)首先,Java虚拟机确定是否已经记录了L是由N表示的类或接口的初始化加载器。如果是这样,这个创作的尝试是无效的,并装载抛出的LinkageError类。
...
(5)Java虚拟机标记C作为具有L-作为其限定类加载器和记录,L是C的初始化加载器(§5.3.4)。
如§5.3.5指出,最重要的一点是,每一个ClassLoader
可以定义每个独特的符号名称最多一个班。 它可能会通过委托给不同的装载机返回不同的实例,但那么他们将被铭记为定义加载器。 和解决从引用时,JVM会要求定义加载Class
到另一个Class
。 或跳过要求它作为§当5.3.2状态Class
对于给定的名称和装载机已经存在。
根据JLS 8.4.3.6上同步Class.forName("name")
因此, .class
是做正确的事情,它会工作-在同一个班级,至少。 此外,所有静态synchronized
方法是在同步.class
。 由于它在JLS说,下面几乎是相同的:
class Test {
int count;
synchronized void bump() {
count++;
}
static int classCount;
static synchronized void classBump() {
classCount++;
}
}
class Test {
int count;
void bump() {
synchronized (this) { count++; }
}
static int classCount;
static void classBump() {
try {
synchronized (Class.forName("Test")) {
classCount++;
}
} catch (ClassNotFoundException e) {}
}
}
然而,随着JLS 12.2状态,现在还不能确定时.class
由不同类调用,因为此调用依赖于类装载器:
乖巧的类加载器维护这些属性:
由于相同的名字,一个良好的类加载器应该总是返回相同的类对象。
如果一个类C的类装载程序L1代表装载到另一个加载器L2,则对于发生的直接超类或C中的一个直接超接口,或作为现场的在C型,或作为一个类型的任何类型T在C语言的方法或构造的形式参数,或在C的方法的返回类型,L1和L2应返回相同类的对象。
一个恶意的类加载器可能违反这些属性。 但是,它不能破坏类型系统的安全性,因为对这种Java虚拟机警卫。
所以,如果你使用的是标准的Java类加载器 - 你应该罚款。 如果您使用的是一些自定义的类装载器,但是,你应该注意的错误。
只有当它们具有相同的类加载器。
如果你有一个根类加载器和两个子类加载器的两个子类加载器(即的URLClassLoader)加载的.class每一个classloader一次,他们将工作异步。
加载Sync
根类加载器将被保存。