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