Java 螺纹安全方法

Java 螺纹安全方法,java,multithreading,thread-safety,Java,Multithreading,Thread Safety,我看到可变类的以下构造: public class Doubtful { public static Doubtful getInstance() { DoubtfulContext doubtfulcontext;//LOCAL HEAP VARIABLE //... doubtfulcontext = new DoubtfulContext(s1, new PrincipalName(s), Defau

我看到可变类的以下构造:

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);
    }

    // ...
}
虽然怀疑可能是不可变的,但怀疑上下文肯定是可变的。
这个线程安全吗?

本地堆变量在这里的相关性是什么?

如果类中没有方法或函数访问
可疑上下文
(如果
可疑上下文
也没有修改),并且如果。。。基本上,如果使用正确,它是线程安全的


那句话里有很多“如果”。最好使
可疑上下文
也不可变

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

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

有几种选择:

  • 使所有这些都不可变。在一个静态块中初始化它并将其存储在一个静态变量中(我不是一个真正的静态爱好者-使用像Guice这样的依赖注入框架并注入它会更干净、更灵活-然后在启动时决定它是否为单例)

  • 如果
    doublefulcontext
    没有被共享,并且是唯一有状态的东西,那么它是有状态的,但是任何未来的调用方都会得到它的新实例,那么您的方法就可以了。如果以后将在线程之间传递
    可疑上下文
    ,则可能需要独立地使该线程安全

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


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

正如您所说的
可疑
是不可变的,这使得它是线程安全的:多个线程可以使用相同的
可疑
实例,而不会影响其他线程使用相同的
可疑
实例。因为线程无法更改实例变量(
可疑
是不可变的),而方法局部变量仅限于执行线程

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

doubtfulcontext = new DoubtfulContext(s1, new PrincipalName(s),
        DefaultConfig.getInstance());
...
return new Doubtful(doubtfulcontext);//Publishes the reference to DoubtfulContext
这将违反堆栈限制。还有一种可能性是,多个线程可以访问相同
可疑上下文
实例的共享、可变数据。如果
doublefulcontext
是非线程安全对象,那么这将破坏程序

考虑一个线程
T1
,该线程调用
getInstance
来获取
可疑
的实例,然后它可能与其他线程共享
可疑上下文
引用(与
可疑
一起出现):

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

在第3行,它创建了一个新的执行线程,使用
doublefulcontext
。现在两个线程具有相同的
可疑上下文
。如果
doublefulcontext
是非线程安全的(具有对实例变量的非同步访问),那么这将破坏程序的线程安全性

是的,局部变量是线程安全的。它们在调用方法时创建,在方法结束时销毁。“本地堆变量”是一个非序列。它是一个局部变量,因此逻辑上在堆栈上。如果您为变量和类型指定不同的名称,这也会很有帮助……只要您不使用singleton
DefaultConfig.getInstance()
@vikingsteve:中的任何变量,该方法似乎是线程安全的,以遵循Java命名约定开始-并且为了清晰起见。否则,当您看到
Foo.doSomething()
时,不清楚这是
Foo
类型中的静态方法,还是通过
Foo
变量调用的实例方法。@vikingsteve:Nope-我更关心的是大写的
D
。变量名应该是camelCase而不是PascalCase。(我并没有真正注意到名字是不同的-只是在中间的名字)。即使可疑的上下文正在访问一个文件。我认为这个类不是线程安全的。