2010-05-19 2 views
7

quindi voglio avere un arraylist che memorizza una serie di quotazioni di borsa. ma tengo traccia del prezzo dell'offerta, chiedere il prezzo e l'ultimo prezzo per ciascuno.sincronizzazione delle letture in una raccolta java

ovviamente in qualsiasi momento, l'offerta o l'ultimo di un dato stock può cambiare.

Ho un thread che aggiorna i prezzi e uno che li legge.

Voglio assicurarmi che durante la lettura nessun altro thread stia aggiornando un prezzo. quindi ho guardato la collezione sincronizzata. ma ciò sembra impedire solo la lettura mentre un altro thread aggiunge o elimina una voce all'array.

Così ora sto sul metodo involucro:

public class Qte_List { 
private final ArrayList<Qte> the_list; 

public void UpdateBid(String p_sym, double p_bid){ 
    synchronized (the_list){ 
     Qte q = Qte.FindBySym(the_list, p_sym); 
     q.bid=p_bid;} 
} 

public double ReadBid(String p_sym){ 
    synchronized (the_list){ 
     Qte q = Qte.FindBySym(the_list, p_sym); 
     return q.bid;} 
} 

così quello che voglio fare con questo non è che un thread può essere facendo nulla - la lettura o l'aggiornamento di contenuti di un la_lista - in una sola volta. sono vicino a questo giusto?

grazie.

+0

Si sta tentando di impedire che una scrittura su un oggetto Quotazione avvenga contemporaneamente a una lettura? Se è così, bloccare la raccolta non lo farà. Vedi la mia risposta. – DJClayworth

risposta

0

Come ho capito, si sta utilizzando la mappa per memorizzare le virgolette; il numero di virgolette non cambia mai, ma ogni citazione può essere letta o modificata per riflettere i prezzi correnti. È importante sapere che il blocco della raccolta protegge solo dalle modifiche a cui gli oggetti Quote si trovano sulla mappa: non limita in alcun modo la modifica del contenuto di tali Quotes. Se si desidera limitare tale accesso, è necessario fornire il blocco sull'oggetto Quote.

Guardando il tuo codice tuttavia non credo che tu abbia un significativo problema di sincronizzazione. Se si tenta di eseguire una lettura contemporaneamente a una scrittura, si otterrà il prezzo prima o il prezzo dopo la scrittura. Se non sapessi che la scrittura sarebbe avvenuta, ciò non dovrebbe importarti. Potrebbe essere necessario blocco a un livello superiore in modo che

if (getBidPrice(mystock)<10.0) { 
    sell(10000); 
} 

accade come un'operazione atomica e non si finisce per vendere a 5,0 anziché 10,0.

Se il numero di virgolette non cambia in realtà, suggerirei di consentire l'aggiunta di oggetti Qte solo nel costruttore di Qte_List. Ciò renderebbe irrilevante il blocco della raccolta. Il termine tecnico per questo sta rendendo Qte_List immutabile.

+0

grazie mi fai pensare che ho bisogno di chiarire più precisamente cosa bloccare. noodle su di esso un paio d'ore. – jeff

+0

DJ - anche, penso di essermi confuso ora nel cercare di riflettere su questo. sto guardando quello che hai scritto in grassetto sopra .... qual è la differenza tra il blocco su una collezione e la marcatura finale? Pensavo che contrassegnarlo definitivo fosse ciò che ha impedito i cambiamenti a cui gli oggetti sono nella mappa. – jeff

+0

@Jeff final dichiara solo la variabile come "immutabile", non l'oggetto nella variabile. Quindi la lista è ancora mutevole. Se vuoi che l'Elenco sia immutabile, consulta 'Collections.unmodifiableList()' – Hardcoded

1

Sì, questo funzionerà, in ogni caso non c'è bisogno di farlo da soli in quanto è già implementata nelle collezioni quadro

Collections.synchronizedList

+1

Un elenco sincronizzato non funzionerà, poiché aggiorna gli attributi delle voci nell'elenco in quel blocco sincronizzato. – Hardcoded

1

Che assomiglia a un approccio ragionevole. Nit-picking, però, probabilmente non dovrebbe includere l'istruzione return all'interno del blocco sincronizzato:

public double ReadBid(String p_sym){ 
    double bid; 
    synchronized (the_list) { 
     Qte q = Qte.FindBySym(the_list, p_sym); 
     bid = q.bid; 
    } 

    return bid; 
} 

non sono sicuro se è solo il mio gusto o c'è qualche concorrenza Gotcha coinvolti, ma per lo meno è sembra più pulito per me ;-).

2

Sì, sei sulla buona strada e dovrebbe funzionare.

Ma perché non utilizzare la raccolta Hashtable esistente, che è sincronizzata e fornisce già una ricerca valore-chiave?

+2

Hashtable (e Vector) sono pre-JDK 1.2 e dovrebbero essere evitati. Invece, considera Collections.synchronizedMap (Map m) per creare una HashMap thread-safe. Inoltre, sebbene l'OP non lo abbia dichiarato esplicitamente, sospetto che le citazioni debbano essere ordinate secondo un tipico portafoglio di ordini. – Adamski

1

Il tuo approccio dovrebbe fare il trucco, ma come hai affermato, ci può essere solo un lettore e uno scrittore alla volta. Questo non è molto scalabile.

Ci sono alcuni modi per migliorare le prestazioni senza perdere la sicurezza del thread qui.
Ad esempio, è possibile utilizzare un ReadWriteLock. Ciò consentirà più lettori alla volta, ma quando qualcuno ottiene il blocco della scrittura, tutti gli altri devono attendere che finisca.

Un altro modo sarebbe utilizzare una raccolta adeguata. Sembra che tu possa scambiare la tua lista con un'implementazione thread-safe di Map. Dai uno sguardo allo ConcurrentMap documentation per possibili candidati.

Edit:
Supponendo che è necessario ordinare per la mappa, uno sguardo all'interfaccia ConcurrentNavigableMap.

1

Ciò che funziona funzionerà, ma il blocco dell'intero elenco ogni volta che si desidera leggere o aggiornare il valore di un elemento non è scalabile. Se questo non ha importanza, allora stai bene con quello che hai. Se vuoi renderlo più scalabile, considera quanto segue ...

Non hai detto se devi essere in grado di apportare modifiche strutturali a the_list (aggiunta o rimozione di elementi), ma in caso contrario, un grande miglioramento sarebbe spostare la chiamata a FindBySym() all'esterno di il blocco sincronizzato. Quindi, invece di sincronizzarsi su the_list, puoi semplicemente sincronizzare su q (l'oggetto Qte). In questo modo è possibile aggiornare contemporaneamente diversi oggetti Qte. Inoltre, se è possibile rendere immutabili anche gli oggetti Qte, in realtà non è necessaria alcuna sincronizzazione. (per aggiornare, basta usare the_list [i] = new Qte (...)).

Se è necessario essere in grado di apportare modifiche strutturali all'elenco, è possibile utilizzare un ReentrantReadWriteLock per consentire letture concorrenti e scritture esclusive.

Sono anche curioso di sapere perché si desidera utilizzare un ArrayList piuttosto che un HashMap sincronizzato.

+0

sembra una hashmap che ha molto più senso. probabilmente di solito elencare troppo senza pensare. la cosa immutabile su un singolo oggetto Qte potrebbe aiutare parte del problema. ma ho bisogno di lavorare un po 'di più per capirlo. qual è la sintassi che rende immutabili gli oggetti Qte, o cercherò. inoltre, immutabile significa che per 'cambiare' l'oggetto che ho bisogno di riassegnarlo? (sto osservando il testo nella risposta che dice "per aggiornare, basta usare la lista [i] = nuovo Qte (...)" – jeff

+0

Immutabile significa "non può essere modificato". Ad esempio, le stringhe sono immutabili, mentre StringBuffer sono mutevole Non è possibile modificare il valore di un oggetto String (ad esempio, non si può dire String s = "a"; s.append ("b");. Una classe di Qte immutabile avrebbe un prezzo di offerta, chiedere prezzo e ultimo prezzo come variabili del membro finale e questi 3 valori sarebbero passati al costruttore.Le variabili membro possono essere pubbliche o puoi avere un getter (ma nessun setter) per ciascuno. – Angus

+0

Inoltre, riguardo al commento di DJClayworth che "tu o ottenere il prezzo prima o il prezzo dopo la scrittura ", questo è vero solo se Qte.bid è un valore o volatile di 32 bit (o inferiore).Per i valori non volatili a 64 bit è possibile leggere nel mezzo di una scrittura e ottenere dati non validi (vedere le specifiche del linguaggio Java, sezione 17.7 per i dettagli), quindi è necessario modificare Qte.bid per essere un float o int o lasciare un doppio e dichiararlo volatile (se non lo è già). Una volta che hai fatto, puoi tranquillamente leggere e scrivere q.bid senza sincronizzazione. (e puoi ignorare il mio suggerimento di immutabilità) – Angus