Domanda

Sto tentando di risolvere un errore intermittente che sembra correlato alla rimozione di un oggetto da una HashMap e quindi al ripristino dello stesso oggetto utilizzando una nuova chiave. My HashMap è creato come segue:

transactions = new HashMap<Short, TransactionBase>();

Il codice che esegue la riassegnazione è il seguente:

transactions.remove(transaction.tran_no);
transaction.tran_no = generate_transaction_id();
transactions.put(transaction.tran_no, transaction);

Il comportamento intermittente che sto vedendo è quel codice che viene eseguito immediatamente dopo ciò che dipende dal fatto che l'oggetto transazione sia localizzabile non sembra trovare l'oggetto transazione usando il nuovo ID transazione. Tuttavia, in futuro, la transazione può essere localizzata. Quindi tirando le cannucce, c'è qualche tipo di effetto asincrono da mettere () o rimuovere che può causare questo tipo di comportamento?

Devo dire che, per quanto ne so, al contenitore si accede da un solo thread. Ho già letto nella documentazione che la classe HashMap non è "sincronizzata".

È stato utile?

Soluzione

Non ci sono " asincrono " effetti nella classe HashMap. Non appena metti qualcosa dentro, è lì. Dovresti controllare due volte e tre volte per assicurarti che non ci siano problemi di threading.

L'unica altra cosa a cui riesco a pensare è che stai facendo una copia della HashMap da qualche parte. La copia ovviamente non sarà influenzata dall'aggiunta di elementi nell'originale o viceversa.

Altri suggerimenti

C'è una leggera differenza tra remove / get e put (anche se la mia ipotesi è che hai un problema di threading).

Il parametro per rimuovi / get è di tipo Oggetto ; per put è di tipo K . Il motivo è stato affermato molte volte in precedenza. Ciò significa che ha problemi con la boxe. Non ho nemmeno intenzione di indovinare quali sono le regole. Se un valore viene inscatolato come Byte in un punto e Short in un altro, questi due oggetti non possono essere uguali.

Esiste un problema simile con List.remove (int) e List.remove (Object) .

Presumo che ogni volta che verifichi la presenza dell'articolo stai sicuramente usando un short o Short topic su Map.get () o Map.contains () ?

Questi metodi accettano argomenti Object, quindi se gli passi un int verrà convertito in un Integer e non corrisponderà mai a nessun elemento nella tua mappa perché avranno tutti Tasti brevi .

Solo un suggerimento ... ti stai concentrando sugli accessi a HashMap ma mi chiedo se dovresti anche vedere se il tuo generate_transaction_id () è thread-safe o se si sta comportando in modo inaspettato.

Hai sovrascritto equals () ma non hashCode () negli oggetti del tuo modello? Che ne dici di compareTo () ? Se si sbagliano, le Collezioni si comporteranno in modo davvero strano.

Controlla le pratiche Java su equals () e compareTo () .

Cosa fa questa funzione generate_transaction_id ()? Se sta generando una cosa simile a GUID a 16 bit, potresti facilmente ottenere collisioni di hash. In combinazione con il threading, potresti ottenere:

T1: transaction1.tran_no = generate_transaction_id();    => 1729
T2: transaction2.tran_no = generate_transaction_id();    => 1729
T1: transactions.put(transaction1.tran_no, transaction1); => map.put(1729, transaction1)
T2: transactions.put(transaction2.tran_no, transaction2); => map.put(1729, transaction2)
T1: int tran_no = transactions.get(1729);               => transaction2
T1: transactions.remove(transaction.tran_no);           => map.remove(1729)
T2: int tran_no = transactions.get(1729);               => null

Naturalmente, questa potrebbe essere una soluzione solo se quella parte "al meglio delle tue conoscenze" non è vera.

Quindi sai che HashMap non è thread-safe. Sei sicuro che vi si acceda da un solo thread? Dopotutto, errori intermittenti sono spesso correlati al threading. In caso contrario, puoi avvolgerlo con Collections.synchronizedMap () , in questo modo:

Collections.synchronizedMap(transactions);

Puoi sempre solo provare in modo da poter eliminare quella possibilità.

Va ??sottolineato che questo avvolge semplicemente la mappa originale con una con tutti i metodi sincronizzati. È possibile prendere in considerazione l'utilizzo di un blocco sincronizzato se l'accesso è localizzato.

Il threading è già stato menzionato in alcune risposte, ma hai considerato il problema di visibilità per gli oggetti utilizzati da più thread? È possibile (e abbastanza comune) che se si inserisce un oggetto in una raccolta in un thread, non sarà "pubblicato". ad altri thread a meno che tu non sia stato correttamente sincronizzato sulla raccolta.

Discussioni e blocchi

Sincronizzazione e sicurezza dei thread in Java

Come altri hanno osservato, DEVI sapere se HashMap è accessibile da un solo thread oppure no. CollectionSpy è un nuovo profiler che ti consente di scoprire istantaneamente, per tutti i container, quanti thread eseguono qualsiasi accesso. Vedi www.collectionspy.com per maggiori dettagli.

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