我是否在以下代码中同步对象实例?我可以安全地做到吗?
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");
}
}
}
答案 0 :(得分:3)
根据Class.forName("name")
同步.class
,因此,synchronized
是正确的事情,它将起作用 - 至少在同一个班级。此外,所有静态.class
方法都在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中所说,以下几乎是相同的:
.class
但是,正如JLS 8.4.3.6所述,不确定何时由不同的类调用{{1}},因为此调用依赖于类加载器:
表现良好的类加载器维护这些属性:
给定相同的名称,一个好的类加载器应该总是返回相同的类对象。
如果类加载器L1将类C的加载委托给另一个加载器L2,那么对于作为直接超类或者超类的任何类型T C的直接超接口,或C中的字段类型,或者 C中方法或构造函数的形式参数的类型,或者 C,L1和L2中的方法的返回类型应该返回相同的类 对象
恶意类加载器可能违反这些属性。但是,它不能破坏类型系统的安全性,因为Java虚拟机可以防范这种情况。
因此,如果您使用标准Java类加载器 - 您应该没问题。但是,如果您使用的是某些自定义类加载器,则应注意错误。
答案 1 :(得分:1)
您必须区分{em>正在加载 Class
和解析 a Class
。
类文字和特殊方法Class.forName(…)
与方法ClassLoader.loadClass(…)
不同。虽然ClassLoader
可能会以奇怪的方式实现后者,例如通过在每次调用时返回不同的实例,JVM将每个上下文解析每个类一次,并记住结果。
重要的是,如果符号引用的分辨率可以重定向,static final
变量也无济于事。如果JVM中有两个相同Class
的实例,则它们的static final
字段也会存在两个不同版本。
Class
实例与每个类数据的JVM之间存在一对一的映射。
引用一些官方词语:
JVMSpec § 5.3.2. Loading Using a User-defined Class Loader
...首先,Java虚拟机确定L是否已被记录为由N表示的类或接口的初始加载器。如果是,则此类或接口是C,并且不需要创建类。 ...
...
JVMSpec § 5.3.5. Deriving a Class from a class File Representation
以下步骤用于使用加载器L从类文件格式的声称表示中派生N表示的非阵列类或接口C的Class对象。
(1)首先,Java虚拟机确定它是否已经记录了L是由N表示的类或接口的启动加载器。如果是,则此创建尝试无效并且加载会引发LinkageError。
...
(5)Java虚拟机将C标记为L作为其定义的类加载器,并记录L是C的初始加载器(§5.3.4)。
第5.3.5节指出的重点是每个ClassLoader
每个唯一的符号名称最多可以定义一个类。它可能通过委托给不同的加载器返回不同的实例,但随后它们将被记住为定义加载器。在解析从Class
到另一个Class
的引用时,JVM将询问定义加载器。或者,当给定名称和加载器的Class
已经存在时,请跳过将其视为§5.3.2状态。
答案 2 :(得分:0)
只有他们有相同的类加载器。
如果你有一个root-classloader和两个child-class-loader,那么两个child-class-loader(即URLClassLoader)每个类加载器加载一次.class,它们将工作异步。
在root-classloader中加载Sync
将保存。