0

我看到一个可变类的以下结构:

public class Doubtful
{

    public static Doubtful getInstance()
    {
        DoubtfulContext doubtfulcontext;//LOCAL HEAP VARIABLE
        //...
        doubtfulcontext = new DoubtfulContext(s1, new PrincipalName(s),
            DefaultConfig.getInstance());
        //...
        doubtfulcontext.setDoubtfulStore(new DoubtfulStore(new File(s2)));
        doubtfulcontext.setKeyTab(...);
        doubtfulcontext.setSupportedEncryptionTypes(ai);
        //...
        return new Doubtful(doubtfulcontext);
    }

    // ...
}

虽然 Doubtful 可能是不可变的,但 DoubtContext 绝对是可变的。
这是线程安全的吗?
这里局部堆变量的相关性是什么?

4

3 回答 3

1

局部变量仅限于执行线程。它们存在于执行线程的堆栈中,其他线程无法访问。这使得getInstance方法线程的执行是安全的。

正如您所说Doubtful,它是不可变的,这使其成为线程安全的:多个线程可以使用同一个Doubtful实例,而不会影响其他使用同一个实例的线程Doubtful。因为线程不能改变实例变量(Doubtful是不可变的)并且方法局部变量被限制在执行线程中。

现在DoubtfulContext是可变的,您正在发布对DoubtfulContext在方法中本地创建的实例的引用getInstance

doubtfulcontext = new DoubtfulContext(s1, new PrincipalName(s),
        DefaultConfig.getInstance());
...
return new Doubtful(doubtfulcontext);//Publishes the reference to DoubtfulContext

这将违反堆栈限制。并且有可能多个线程可以访问同一DoubtfulContext实例的共享可变数据。如果DoubtfulContext是一个非线程安全的对象,那么这会破坏你的程序。

考虑一个T1调用getInstance以获取实例的线程,Doubtful然后它可能与其他线程共享DoubtfulContext引用(与 一起出现):Doubtful

1. Doubtful doubtful = Doubtful.getInstance();
2. DoubtfulContext doubtfulContext = doubtful.getDoubtfulContext();
3. new Thread(new SomeRunnable(doubtfulContext)).start();
4. doubtfulContext.chnageSomeState();

在第 3 行,它使用DoubtfulContext. 现在两个线程具有相同的DoubtfulContext. 如果DoubtfulContext是非线程安全的(对实例变量进行非同步访问),那么这将破坏程序的线程安全。

于 2013-10-23T10:50:42.543 回答
0

目前尚不清楚该代码的作用是否可以确定它是否是正确的选择。线程安全的问题是什么是可变的,以及该对象是否会被多个线程看到。创建一个有状态但只能被一个线程看到的新对象是线程安全的。创建一个包含所有不可变成员的不可变对象是线程安全的,无论您是返回一个新对象还是重复返回相同的对象。

如果你有可变状态,你必须知道对象是否会被多个线程看到。如果是,那么您需要采取措施确保可变事物是线程安全的。

几个选项:

  • 让所有的东西不可变。将它初始化在一个静态块中并将其存储在一个静态变量中(我不是静态的忠实粉丝 - 使用像 Guice 这样的依赖注入框架并注入它会更干净、更灵活 - 然后决定它是否是一个是否单例在启动时生成)。

  • 如果doubtfulContext不是共享的,并且是唯一有状态的东西 - 那么它是有状态的,但是任何未来的调用者都会获得它的新实例,那么你的方法就可以了。如果doubtfulContext稍后将在线程之间传递,您可能需要独立地使该线程安全

  • 如果您想通过仅读取一次同一个文件并共享代表该文件的对象来进行优化,那么您将需要某种线程安全缓存

于 2013-10-23T08:12:43.603 回答
0

这种构造看起来是线程安全的,如果没有方法或函数可以访问doubtfulcontext类中的其他地方(并且如果doubtfulcontext也没有修改),并且如果......基本上如果你正确使用它,它就是线程安全的。

这句话中有很多如果。最好也使DoubtfulContext不可变。

于 2013-10-23T07:03:49.577 回答