Desidero elaborare un flusso di richieste client. Ogni richiesta ha il suo tipo speciale. Per prima cosa ho bisogno di inizializzare alcuni dati per quel tipo, dopodiché posso iniziare ad elaborare le richieste. Quando il tipo di client arriva per la prima volta, ho appena inizializzato i dati corrispondenti. Successivamente, tutte le seguenti richieste di quel tipo vengono elaborate utilizzando tali dati.Questo codice è un thread sicuro?
Ho bisogno di farlo in un modo sicuro per thread.
Ecco un codice che ho scritto. È thread-safe?
public class Test {
private static Map<Integer, Object> clientTypesInitiated = new ConcurrentHashMap<Integer, Object>();
/* to process client request we need to
create corresponding client type data.
on the first signal we create that data,
on the second - we process the request*/
void onClientRequestReceived(int clientTypeIndex) {
if (clientTypesInitiated.put(clientTypeIndex, "") == null) {
//new client type index arrived, this type was never processed
//process data for that client type and put it into the map of types
Object clientTypeData = createClientTypeData(clientTypeIndex);
clientTypesInitiated.put(clientTypeIndex, clientTypeData);
} else {
//already existing index - we already have results and we can use them
processClientUsingClientTypeData(clientTypesInitiated.get(clientTypeIndex));
}
}
Object createClientTypeData(int clientIndex) {return new Object();}
void processClientUsingClientTypeData(Object clientTypeData) {}
}
Da un lato, ConcurrentHashMap non può produrre map.put (A, B) == nulli due volte per lo stesso A. Da altra parte, l'operazione di assegnazione e comparisson non è thread-safe.
Quindi questo codice è ok? In caso contrario, come posso risolverlo?
AGGIORNAMENTO: Ho accettato la risposta di Martin Serrano perché il suo codice è thread-safe e non è soggetto a un doppio problema di inizializzazione. Ma vorrei sottolineare che non ho trovato alcun problema con la mia versione, pubblicato come risposta sotto, e la mia versione non richiede la sincronizzazione.
Penso che sia necessario un 'else' prima di' processClientUsingClientTypeData'. – Gray
Anche questo non è thread-safe! Aspetto: un thread esegue get, confronta con null, passa if, quindi un altro thread fa lo stesso, quindi uno assegna a clientTypeData e alla fine ritorna dal metodo, ma un altro thread sovrascrive il clientTypeData. –
@Krzysztof cosa non è sicuro? come ho detto, _se non ti dispiace a volte eseguire createClientTypeData più di una volta, questo va bene. nel caso che descrivi, il secondo thread sostituirà semplicemente il risultato del primo. presumibilmente dal momento che ogni richiesta potrebbe attivare l'inizializzazione, quindi produrrà sempre gli stessi risultati. se l'inizializzazione è _really_ costoso, è possibile aggiungere più complessità per evitarlo. –