14

鉴于:

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() 方法声明为静态将使类成为线程安全的。

F. 将 doThings() 中的语句包装在 synchronized(new Object()) { } 块中将使类成为线程安全的。

将 doThings() 标记为同步以使该类线程安全还不够吗?我看到正确答案是 D,但这个问题的模型答案是 E,但我不明白为什么?

4

5 回答 5

19

E. 将 doThings() 方法声明为静态将使类成为线程安全的。

这是一个棘手的答案。该方法已经同步,但在实例上,而状态在静态字段中,即在类上。使它static synchronized确实是正确的答案,因为它会在类上同步,而不是在(无意义的)实例上同步。

D. 变量“x”中的数据受到保护,不会出现并发访问问题。

private static int x;

这是一个静态变量。它由类的所有实例共享,因此在单个实例上同步没有帮助,就像 F 没有帮助一样,它在完全丢弃的虚拟对象上同步。

于 2012-09-06T03:25:25.237 回答
12

根据语言规范

同步方法在执行之前获取监视器(第 17.1 节)。

对于类(静态)方法,使用与方法类的 Class 对象关联的监视器。

对于实例方法,使用与 this(调用该方法的对象)关联的监视器。

这意味着在您提供的代码中,关键字会导致方法在执行方法主体之前synchronized获得锁定。this但是,因为xstatic并不能确保更新x是原子的。(该类的另一个实例可以进入同步区域并同时进行更新,因为它们具有不同的this值,因此具有不同的锁。)

但是,声明doStuffstatic 将使对该方法的所有调用都获得相同的锁(在 上的那个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) {
            // ...
        }
    }
}
于 2012-09-06T03:27:11.807 回答
6

通过同步 doThings() 方法,您持有特定 TestSeven 对象的锁。但是,类的静态变量不属于对象本身的具体实例。它们属于 Class 对象TestSeven.class。所以,要么你可以去

synchronized (TestSeven.class){
    int current = x;
    current++;
    x = current;
}

在你的 doThings() 方法中,该方法正在获取实例锁中的类锁,这是过度的事情。因此,您可以将该方法标记为静态,以便最终单独获取 Class 对象的锁。

于 2012-09-06T03:27:20.697 回答
1

由于其他线程可以在方法运行的同时对其进行修改x。制作将阻止这一点。staticdoThingsdoThings static

于 2012-09-06T03:58:50.090 回答
-6

我同意你的观点,正确答案是 D。我会说 E 不正确,因为如果我将 doThings() 设置为静态并删除同步关键字,我可以只启动 50 个 TestSeven 线程,这可能会导致不正确的 x 值。

注意:我在这里错了,我错过了没有静态的同步方法实际上使用实例作为锁监视器而不是类本身的观点。

于 2012-09-06T03:29:14.587 回答