Jackson库的ObjectMapper类似乎是线程安全的。

这是否意味着我应该像这样将ObjectMapper声明为静态字段

class Me {
    private static final ObjectMapper mapper = new ObjectMapper();
}

而不是像这样的实例级字段?

class Me {
    private final ObjectMapper mapper = new ObjectMapper();
}

当前回答

这个问题可能很老了,但我是这么做的。

将ObjectMapper实例保存在线程安全的单例中:

public final class JacksonObjectMapperHolder {

  private static volatile JacksonObjectMapperHolder INSTANCE;

  private static final Object MUTEX = new Object();

  public static JacksonObjectMapperHolder getInstance() {
    JacksonObjectMapperHolder instance = INSTANCE;

    if(instance == null) {
      synchronized(MUTEX) {
        instance = INSTANCE;

        if(instance == null) {
          INSTANCE = instance = new JacksonObjectMapperHolder();
        }
      }
    }

    return instance;
  }

  private final ObjectMapper objectMapper = new ObjectMapper();

  private JacksonObjectMapperHolder() {
    super();
  }

  public final ObjectMapper getObjectMapper() {
    return objectMapper;
  }

}

其他回答

尽管ObjectMapper是线程安全的,但我强烈反对将其声明为静态变量,特别是在多线程应用程序中。 甚至不是因为这是一种糟糕的实践,而是因为您面临着严重的死锁风险。我是根据自己的经验讲的。我创建了一个具有4个相同线程的应用程序,用于从web服务获取和处理JSON数据。 根据线程转储,我的应用程序经常在执行以下命令时暂停:

Map aPage = mapper.readValue(reader, Map.class);

除此之外,表现并不好。 当我用基于实例的变量替换静态变量时,失速消失了,性能翻了两番。也就是说,240万个JSON文档在40分56秒内被处理。而不是之前的2.5小时。

是的,这是安全的,也是推荐的。

您所提到的页面中唯一需要注意的是,一旦共享了映射器,您就不能修改它的配置;但是你没有改变构型,所以这很好。如果你确实需要改变配置,你可以从静态块来做,这也会很好。

编辑:(2013/10)

在2.0及以上版本中,可以通过注意有一种更好的方法来增强上述内容:使用ObjectWriter和ObjectReader对象,它们可以由ObjectMapper构造。 它们是完全不可变的、线程安全的,这意味着理论上甚至不可能导致线程安全问题(如果代码试图重新配置实例,则ObjectMapper可能会出现线程安全问题)。

这个问题可能很老了,但我是这么做的。

将ObjectMapper实例保存在线程安全的单例中:

public final class JacksonObjectMapperHolder {

  private static volatile JacksonObjectMapperHolder INSTANCE;

  private static final Object MUTEX = new Object();

  public static JacksonObjectMapperHolder getInstance() {
    JacksonObjectMapperHolder instance = INSTANCE;

    if(instance == null) {
      synchronized(MUTEX) {
        instance = INSTANCE;

        if(instance == null) {
          INSTANCE = instance = new JacksonObjectMapperHolder();
        }
      }
    }

    return instance;
  }

  private final ObjectMapper objectMapper = new ObjectMapper();

  private JacksonObjectMapperHolder() {
    super();
  }

  public final ObjectMapper getObjectMapper() {
    return objectMapper;
  }

}

如果你不想将它定义为静态final变量,但又想节省一点开销并保证线程安全,我从这个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();
}

归功于作者。

com .杰克逊fasterxml。databind 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的另一个原因