使类线程安全

Jav*_*yer 14 java synchronization thread-safety

鉴于:

public class TestSeven extends Thread {

private static int x;

public synchronized void doThings() {
    int current = x;
    current++;
    x = current;
}

public void run() {
    doThings();
  }
}
Run Code Online (Sandbox Code Playgroud)

哪个论述是对的?

A.编译失败.

B.在运行时抛出异常.

C.同步run()方法会使类成为线程安全的.

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

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

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

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

Thi*_*ilo 19

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

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

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

private static int x;
Run Code Online (Sandbox Code Playgroud)

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


Dao*_*Wen 12

根据语言规范:

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

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

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

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

但是,声明doStuffstatic将使对方法的所有调用都获得相同的锁(对象上的那个Class),从而确保方法体中的互斥.

规范确实说明:

class A {
    static synchronized void doSomething() {
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

与字面意思完全相同

class A {
    static void doSomething() {
        synchronized(A.class) {
            // ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

同理:

class B {
    synchronized void doSomething() {
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

与字面意思完全相同

class B {
    void doSomething() {
        synchronized (this) {
            // ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Aru*_*nan 6

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

synchronized (TestSeven.class){
    int current = x;
    current++;
    x = current;
}
Run Code Online (Sandbox Code Playgroud)

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