Jackson库的ObjectMapper
类彷佛是线程安全的 。 git
这是否意味着我应该像这样将个人ObjectMapper
声明为静态字段? github
class Me { private static final ObjectMapper mapper = new ObjectMapper(); }
而不是像这样的实例级字段? 安全
class Me { private final ObjectMapper mapper = new ObjectMapper(); }
尽管就线程安全而言,声明静态ObjectMapper是安全的,可是您应该意识到,在Java中构造静态Object变量被认为是很差的作法。 有关更多详细信息,请参见为何将静态变量视为邪恶? (若是您愿意, 个人回答 ) 多线程
简而言之,应避免使用静态方法,由于这样会使编写简洁的单元测试变得困难。 例如,对于静态最终ObjectMapper,您没法将JSON序列化换成虚拟代码或无操做。 app
另外,静态的final阻止您在运行时从新配置ObjectMapper。 您可能如今没有想到这样作的缘由,可是若是您将本身锁定在静态的最终模式中,那么只需拆除类加载器,就能够从新初始化它。 ide
在使用ObjectMapper的状况下,它很好,但总的来讲,这是一种很差的作法,而且使用单例模式或控制反转来管理您的长期对象没有任何优点。 性能
尽管ObjectMapper是线程安全的,但我强烈建议不要将其声明为静态变量,尤为是在多线程应用程序中。 甚至不是由于这是一种很差的作法,而是由于您面临着严重的死锁风险。 我是根据本身的经验讲的。 我建立了一个具备4个相同线程的应用程序,这些线程正在从Web服务获取和处理JSON数据。 根据线程转储,个人应用程序常常停在如下命令上: 单元测试
Map aPage = mapper.readValue(reader, Map.class);
除此以外,性能也不佳。 当我将静态变量替换为基于实例的变量时,停滞消失了,性能提升了三倍。 也就是说,在40分钟56秒内处理了240万个JSON文档,而不是以前的2.5个小时。 测试
是的,这是安全的,建议您这样作。 spa
您所引用页面的惟一警告是,共享器一旦被共享就没法修改。 可是您不更改配置,这样就能够了。 若是确实须要更改配置,则能够从静态块执行此操做,也能够。
编辑 :(2013/10)
在2.0及更高版本中,能够经过注意到还有一个更好的方法来加强上述功能:使用ObjectWriter
和ObjectReader
对象,它们能够由ObjectMapper
构造。 它们是彻底不变的,线程安全的,这意味着从理论上讲甚至不可能致使线程安全问题(若是代码尝试从新配置实例,则可能在ObjectMapper
发生)。
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的另外一个缘由
若是您不想将其定义为静态最终变量,但想节省一些开销并确保线程安全,则能够今后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(); }
归功于做者。