[英]Making a class Thread-Safe
鉴于:
public class TestSeven extends Thread {
private static int x;
public synchronized void doThings() {
int current = x;
current++;
x = current;
}
public void run() {
doThings();
}
}
哪个论述是对的?
A.编译失败。
B.在运行时抛出异常。
C.同步run()方法会使类成为线程安全的。
D.变量“x”中的数据受到保护,不会出现并发访问问题。
E.将doThings()方法声明为static将使类成为线程安全的。
F.在同步(new Object()){}块中包装doThings()中的语句将使该类成为线程安全的。
是不是足以将doThings()标记为已同步以使该类具有线程安全性? 我看到正确答案是D但这个问题的模型答案是E,但我不明白为什么?
E.将doThings()方法声明为static将使类成为线程安全的。
这是一个棘手的答案。 该方法已经同步,但在实例上,而状态是在静态字段中,即在类上。 使它static synchronized
确实是正确的答案,因为它在类上同步,而不是在(无意义的)实例上同步。
D.变量“x”中的数据受到保护,不会出现并发访问问题。
private static int x;
这是一个静态变量。 它由类的所有实例共享,因此在单个实例上进行同步是没有用的,就像F没有帮助的方式一样,它在完全丢弃的虚拟对象上同步。
根据语言规范 :
同步方法在执行之前获取监视器(第17.1节)。
对于类(静态)方法,使用与方法类的Class对象关联的监视器。
对于实例方法,使用与此关联的监视器(调用该方法的对象)。
这意味着,在该代码时所提供的synchronized
关键字使获得的锁的方法this
执行该方法的前体。 但是,由于x
是static
,因此无法确保对x
的更新是原子的。 (该类的另一个实例可以进入同步区域并同时进行更新,因为它们具有不同的this
值,因此具有不同的锁定。)
但是,声明doStuff
static会使对方法的所有调用都获得相同的锁( Class
上的那个),从而确保方法体中的互斥。
规范确实说明:
class A {
static synchronized void doSomething() {
// ...
}
}
与字面意思完全相同
class A {
static void doSomething() {
synchronized(A.class) {
// ...
}
}
}
同理:
class B {
synchronized void doSomething() {
// ...
}
}
与字面意思完全相同
class B {
void doSomething() {
synchronized (this) {
// ...
}
}
}
通过同步doThings()方法,您将持有特定TestSeven对象的锁。 但是,类的静态变量不属于对象本身的特定实例。 它们属于Class对象TestSeven.class
。 所以,要么你可以去找一个
synchronized (TestSeven.class){
int current = x;
current++;
x = current;
}
在你的doThings()方法中,它正在一个实例锁中获取类锁,这是一个过度的东西。 因此,您可以将方法标记为静态,以便最终单独获取Class对象的锁定。
由于x
是static
其他线程可以在运行doThings
方法的同时修改它。 使doThings
static
将阻止这一点。
我同意你的正确答案是D.我会说E是不正确的,因为如果我将doThings()设置为静态并删除synchronized关键字,我可以启动50个TestSeven线程,它可能导致不正确的x值。
注意:我在这里错了,我错过了没有静态的synchronized方法实际上使用实例作为锁定监视器而不是类本身。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.