我看到了一个可变类的以下构造:
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肯定是可变的 这是线程安全的吗? 这里的局部堆变量的相关性是什么?
答案 0 :(得分:2)
局部变量局限于执行线程。它们存在于执行线程的堆栈中,并且其他线程无法访问。这使得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();
引用})与其他线程:
DoubtfulContext
在第3行,它使用DoubtfulContext
创建一个新的执行线程。现在两个线程具有相同的DoubtfulContext
。如果{{1}}是非线程安全的(对实例变量具有非同步访问权限),那么这将破坏程序的线程安全性。
答案 1 :(得分:0)
如果没有方法或函数可以访问类中其他位置的doubtfulcontext
(如果doubtfulcontext
未被修改),那么这个结构看起来是线程安全的,如果......基本上如果你使用它,它是线程安全的。
该句子中有很多 ifs 。最好使DoubtfulContext
也不可变。
答案 2 :(得分:0)
目前尚不清楚这段代码如果是正确的选择肯定会说些什么。线程安全的问题是什么是可变的问题以及该对象是否会被多个线程看到。创建一个有状态但只能被一个线程看到的新对象是线程安全的。使用所有不可变成员创建不可变对象是线程安全的,无论您是重复返回新的还是同一个。
如果你有可变状态,你必须知道该对象是否会被多个线程看到。如果是,那么您需要采取措施确保可变事物是线程安全的。
有几个选择:
让所有这一切都不可变。在静态块中初始化它并将其存储在一个静态变量中(我不是真正的静态变量 - 它会更清晰,更灵活地使用像Guice这样的依赖注入框架并注入它 - 然后决定它是否是一个单身或不单身是在启动时制作的。)
如果doubtfulContext
未被共享,并且仅是有状态的东西 - 那么它是有状态的,但任何未来的调用者都会获得它的新实例,然后你的方法很好。如果以后在线程之间传递doubtfulContext
,您可能需要独立地创建线程安全
如果你想通过一次只读同一个文件并共享一个代表该文件的对象进行优化,那么你将需要某种线程安全的缓存