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(); }
歸功於做者。