繁体   English   中英

使类线程安全

[英]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执行该方法的前体。 但是,由于xstatic ,因此无法确保对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对象的锁定。

由于xstatic其他线程可以在运行doThings方法的同时修改它。 使doThings static将阻止这一点。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM