Jackson库的ObjectMapper类似乎是线程安全的 。
这是否意味着我应该像这样将我的ObjectMapper声明为静态字段?
class Me {
private static final ObjectMapper mapper = new ObjectMapper();
}
而不是像这样的实例级字段?
class Me {
private final ObjectMapper mapper = new ObjectMapper();
}
#1楼
尽管就线程安全而言,声明静态ObjectMapper是安全的,但是您应该意识到,在Java中构造静态Object变量被认为是不好的做法。 有关更多详细信息,请参见为什么将静态变量视为邪恶? (如果您愿意, 我的回答 )
简而言之,应避免使用静态方法,因为这样会使编写简洁的单元测试变得困难。 例如,对于静态最终ObjectMapper,您无法将JSON序列化换成虚拟代码或无操作。
另外,静态的final阻止您在运行时重新配置ObjectMapper。 您可能现在没有想到这样做的原因,但是如果您将自己锁定在静态的最终模式中,那么只需拆除类加载器,就可以重新初始化它。
在使用ObjectMapper的情况下,它很好,但总的来说,这是一种不好的做法,并且使用单例模式或控制反转来管理您的长期对象没有任何优势。
#2楼
尽管ObjectMapper是线程安全的,但我强烈建议不要将其声明为静态变量,尤其是在多线程应用程序中。 甚至不是因为这是一种不好的做法,而是因为您面临着严重的死锁风险。 我是根据自己的经验讲的。 我创建了一个具有4个相同线程的应用程序,这些线程正在从Web服务获取和处理JSON数据。 根据线程转储,我的应用程序经常停在以下命令上:
Map aPage = mapper.readValue(reader, Map.class);
除此之外,性能也不佳。 当我将静态变量替换为基于实例的变量时,停滞消失了,性能提高了三倍。 也就是说,在40分钟56秒内处理了240万个JSON文档,而不是之前的2.5个小时。
#3楼
是的,这是安全的,建议您这样做。
您所引用页面的唯一警告是,共享器一旦被共享就无法修改。 但是您不更改配置,这样就可以了。 如果确实需要更改配置,则可以从静态块执行此操作,也可以。
编辑 :(2013/10)
在2.0及更高版本中,可以通过注意到还有一个更好的方法来增强上述功能:使用ObjectWriter和ObjectReader对象,它们可以由ObjectMapper构造。 它们是完全不变的,线程安全的,这意味着从理论上讲甚至不可能导致线程安全问题(如果代码尝试重新配置实例,则可能在ObjectMapper发生)。
#4楼
com.fasterxml.jackson.databind.type.TypeFactory._hashMapSuperInterfaceChain(HierarchicType)
com.fasterxml.jackson.databind.type.TypeFactory._findSuperInterfaceChain(Type, Class)
com.fasterxml.jackson.databind.type.TypeFactory._findSuperTypeChain(Class, Class)
com.fasterxml.jackson.databind.type.TypeFactory.findTypeParameters(Class, Class, TypeBindings)
com.fasterxml.jackson.databind.type.TypeFactory.findTypeParameters(JavaType, Class)
com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(ParameterizedType, TypeBindings)
com.fasterxml.jackson.databind.type.TypeFactory._constructType(Type, TypeBindings)
com.fasterxml.jackson.databind.type.TypeFactory.constructType(TypeReference)
com.fasterxml.jackson.databind.ObjectMapper.convertValue(Object, TypeReference)
com.fasterxml.jackson.databind.type.TypeFactory类中的_hashMapSuperInterfaceChain方法已同步。 在高负载下看到相同的竞争。
避免静态ObjectMapper的另一个原因
#5楼
如果您不想将其定义为静态最终变量,但想节省一些开销并确保线程安全,则可以从此PR中了解到一个技巧。
private static final ThreadLocal<ObjectMapper> om = new ThreadLocal<ObjectMapper>() {
@Override
protected ObjectMapper initialValue() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return objectMapper;
}
};
public static ObjectMapper getObjectMapper() {
return om.get();
}
归功于作者。
来源:oschina
链接:https://my.oschina.net/u/3797416/blog/3189657