Domanda

class ObjectMapper della biblioteca Jackson sembra essere thread-safe .

Questo significa che dovrei dichiarare il mio ObjectMapper come un campo statico come questo

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

anziché come un campo a livello di istanza come questo?

class Me {
    private final ObjectMapper mapper = new ObjectMapper();
}
È stato utile?

Soluzione

Sì, che è sicuro e consigliato.

L'unica avvertenza dalla pagina di lei ha fatto riferimento è che non si può essere modificando la configurazione del mapper una volta che è condivisa; ma non si modifica la configurazione in modo che va bene. Se avuto bisogno di modificare la configurazione, si farebbe che dal blocco statico e sarebbe bene pure.

Modifica : (2013/10)

Con 2.0 e superiori, sopra può essere aumentata da notare che c'è un modo migliore: uso ObjectWriter e oggetti ObjectReader, che possono essere costruiti da ObjectMapper. Sono completamente immutabili, thread-safe, il che significa che non è nemmeno teoricamente possibile causare problemi di filo di sicurezza (che possono verificarsi con ObjectMapper se cerca codice per esempio ri-configure).

Altri suggerimenti

Sebbene ObjectMapper è sicuro filo, che sarebbe fortemente scoraggiare da dichiarare come variabile statica, specialmente in applicazioni multithread. Nemmeno perché è una cattiva pratica, ma perché si esegue un rischio pesante di deadlocking. Sto dicendo che dalla mia esperienza personale. Ho creato un'applicazione con 4 fili identici che stavano ottenendo ed elaborazione dei dati JSON dai servizi web. La mia richiesta è stata spesso stallo sul seguente comando, secondo la discarica discussione:

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

Oltre a ciò, le prestazioni non era buono. Quando ho sostituito variabile statica con la variabile basato esempio, la paralisi scomparso e prestazioni quadruplicato. Cioè 2.4 milioni di documenti JSON sono stati trattati in 40min.56sec., Invece di 2,5 ore in precedenza.

Anche se è sicuro di dichiarare un'ObjectMapper statica in termini di sicurezza filo, si deve essere consapevoli che costruire le variabili oggetto statico in Java è considerata una cattiva pratica. Per ulteriori dettagli, vedere Perché sono variabili statiche considerati il ??male (e se vuoi, my )

In breve, statica deve essere evitato perché la rendono difficile unit test concisi scrittura. Ad esempio, con un ObjectMapper finale statico, non è possibile scambiare la serializzazione JSON per il codice fittizio o un no-op.

In aggiunta, una statica impedisce finali da sempre la riconfigurazione ObjectMapper in fase di esecuzione. Non si potrebbe immaginare una ragione per questo ora, ma se vi bloccare in un modello finale statica, a breve nulla di abbattere il classloader vi permetterà di ri-inizializzato.

Nel caso di ObjectMapper il suo bene, ma in generale è una cattiva pratica e non v'è alcun vantaggio rispetto utilizzando un pattern Singleton o l'inversione-di-controllo per gestire i vostri oggetti a lunga vita.

Un trucco che ho imparato da questo PR se non si vuole definirla come una variabile statica finale ma si vuole risparmiare un po 'di thread-safe in testa e garanzia.

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();
}

credito all'autore.

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)

Il metodo _hashMapSuperInterfaceChain nella classe com.fasterxml.jackson.databind.type.TypeFactory è sincronizzato. Sto vedendo contesa sulla stessa con carichi elevati.

Può essere un altro motivo per evitare una statica ObjectMapper

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top