java – 以下实用程序类是否是线程安全的?
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了java – 以下实用程序类是否是线程安全的?,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3577字,纯文字阅读大概需要6分钟。
内容图文
![java – 以下实用程序类是否是线程安全的?](/upload/InfoBanner/zyjiaocheng/751/4c2c10a00c094867b86483f73b73f18a.jpg)
首先让我们看看实用程序类(大多数javadoc已被删除,只是示例):
public class ApplicationContextUtils {
/**
* The application context; care should be taken to ensure that 1) this
* variable is assigned exactly once (in the
* {@link #setContext(ApplicationContext)} method, 2) the context is never
* reassigned to {@code null}, 3) access to the field is thread-safe (no race
* conditions can occur)
*/
private static ApplicationContext context = null;
public static ApplicationContext getContext() {
if (!isInitialized()) {
throw new IllegalStateException(
"Context not initialized yet! (Has the "
+ "ApplicationContextProviderBean definition been configured "
+ "properly and has the web application finished "
+ "loading before you invoked this method?)");
}
return context;
}
public static boolean isInitialized() {
return context == null;
}
@SuppressWarnings("unchecked")
public static <T> T getBean(final String name, final Class<T> requiredType) {
if (requiredType == null) {
throw new IllegalArgumentException("requiredType is null");
}
return (T) getContext().getBean(name, requiredType);
}
static synchronized void setContext(final ApplicationContext theContext) {
if (theContext == null) {
throw new IllegalArgumentException("theContext is null");
}
if (context != null) {
throw new IllegalStateException(
"ApplicationContext already initialized: it cannot be done twice!");
}
context = theContext;
}
private ApplicationContextUtils() {
throw new AssertionError(); // NON-INSTANTIABLE UTILITY CLASS
}
}
最后,有以下辅助Spring托管bean实际调用’setContext’方法:
public final class ApplicationContextProviderBean implements
ApplicationContextAware {
public void setApplicationContext(
final ApplicationContext applicationContext) throws BeansException {
ApplicationContextUtils.setContext(applicationContext);
}
}
应用程序启动后,Spring将调用setApplicationContext方法一次.假设nincompoop以前没有调用ApplicationContextUtils.setContext(),那应该锁定对实用程序类中上下文的引用,允许调用getContext()成功(意味着isInitialized()返回true).
我只是想知道这个类是否违反了良好编码实践的任何原则,特别是线程安全(但是其他的愚蠢行为是受欢迎的).
感谢您帮助我成为更好的程序员,StackOverflow!
问候,
LES
附:我没有说明为什么我需要这个实用程序类 – 让我确实有合法的需要从应用程序中的任何地方的静态上下文中访问它(当然,在加载Spring上下文之后).
解决方法:
不,这不是线程安全的.
对于通过getContext()读取该变量的线程,不保证写入上下文类变量.
至少,声明上下文是不稳定的.理想情况下,将上下文重新定义为AtomicReference,通过以下调用进行设置:
if(!context.compareAndSet(null, theContext))
throw new IllegalStateException("The context is already set.");
这是一个更完整的例子:
public class ApplicationContextUtils {
private static final AtomicReference<ApplicationContext> context =
new AtomicReference<ApplicationContext>();
public static ApplicationContext getContext() {
ApplicationContext ctx = context.get();
if (ctx == null)
throw new IllegalStateException();
return ctx;
}
public static boolean isInitialized() {
return context.get() == null;
}
static void setContext(final ApplicationContext ctx) {
if (ctx == null)
throw new IllegalArgumentException();
if (!context.compareAndSet(null, ctx))
throw new IllegalStateException();
}
public static <T> T getBean(final String name, final Class<T> type) {
if (type == null)
throw new IllegalArgumentException();
return type.cast(getContext().getBean(name, type));
}
private ApplicationContextUtils() {
throw new AssertionError();
}
}
请注意,除了线程安全之外,这还提供了类型安全性,利用了传递给getBean()方法的Class实例.
我不确定你打算如何使用isInitialized()方法;这对我来说似乎没什么用处,因为一旦你打电话给它,情况就会发生变化,你就没有好的方法得到通知.
内容总结
以上是互联网集市为您收集整理的java – 以下实用程序类是否是线程安全的?全部内容,希望文章能够帮你解决java – 以下实用程序类是否是线程安全的?所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。