Perché sono questi così fondamentale che ogni oggetto deve avere loro e è c'è un calo di prestazioni in averli (presumibilmente uno stato viene memorizzato nella loro)?
tl; dr: Sono metodi di sicurezza del filo e hanno costi ridotti rispetto al loro valore.
Le realtà fondamentali che these methods supporto sono che:
- Java è sempre multi-threaded. Esempio: controlla l'elenco dei Thread usati da un processo usando jconsole o jvisualvm un po 'di tempo.
- La correttezza è più importante della "prestazione". Quando stavo valutando i progetti (molti anni fa), dovevo spiegare "arrivare alla risposta sbagliata veramente veloce è ancora sbagliato."
Fondamentalmente, questi metodi forniscono alcuni dei ganci per gestire i monitor per oggetto utilizzati nella sincronizzazione. Specificamente, se ho synchronized(objectWithMonitor)
in un metodo particolare, posso usare objectWithMonitor.wait()
per produrre quel monitor (ad es., Se ho bisogno di un altro metodo per completare un calcolo prima di poter procedere). In tal caso, ciò consentirà un altro metodo che è stato bloccato in attesa che il monitor proceda.
D'altra parte, posso usare objectWithMonitor.notifyAll()
per consentire ai Thread che stanno aspettando il monitor di sapere che ho intenzione di abbandonare presto il monitor. In realtà, non possono procedere finché non esco dal blocco sincronizzato.
Rispetto ad esempi specifici (ad esempio, lunghe liste di Doubles) dove si potrebbe preoccupare che ci sia una performance o la memoria colpire sul meccanismo di monitoraggio, qui ci sono alcuni punti che si dovrebbe probabilmente prendere in considerazione:
- First , Provalo. Se pensi che ci sia un forte impatto da un meccanismo Java di base come la correttezza multi-thread, c'è un'eccellente possibilità che il tuo intuito sia falso. Misura prima l'impatto. Se è una cosa seria e tu rispondi allo allo che non avrai mai bisogno di sincronizzare su un singolo Double, considera invece l'uso del doppio.
- Se non sei sicuro che tu, tuo collaboratore, un futuro programmatore di manutenzione (chi potrebbe essere te stesso un anno dopo), ecc., mai e poi mai , sempre, avremo bisogno di una buona granularità dell'accesso ai tuoi dati, ci sono ottime possibilità che togliere questi monitor renderebbe il tuo codice meno flessibile e manutenibile.
Follow-up in risposta alla domanda su per-Object vs. oggetti espliciti del monitor:
Risposta breve: @JonSkeet: sì, rimuovendo i monitor creerebbe problemi: si creerebbe attrito. Mantenere quei monitor in Object
ci ricorda che questo è sempre un sistema multithread.
I monitor degli oggetti incorporati non sono sofisticati ma sono: facili da spiegare; lavorare in modo prevedibile; e sono chiari nel loro scopo. synchronized(this)
è una chiara dichiarazione di intenti. Se costringiamo i programmatori principianti a utilizzare esclusivamente il pacchetto di concorrenza, introduciamo l'attrito. Cosa c'è in quel pacchetto? Cos'è un semaforo? Fork-join?
Un codificatore inesperto può utilizzare i monitor Oggetto per scrivere codice decente del modello di visualizzazione del modello. synchronized
, wait
e notifyAll
possono essere utilizzati per implementare l'ingenuo (nel senso di prestazioni di sicurezza semplici, accessibili ma forse non all'avanguardia). L'esempio canonico sarebbe uno di questi Doubles (postato dall'OP) che può avere un Thread impostato su un valore mentre il thread AWT ottiene il valore per metterlo su una JLabel. In tal caso, non vi è alcun motivo valido per creare un oggetto aggiuntivo esplicito solo per avere un monitor esterno.
A un livello leggermente più elevato di complessità, questi stessi metodi sono utili come metodo di monitoraggio esterno. Nell'esempio sopra, l'ho fatto esplicitamente (vedi i frammenti objectWithMonitor sopra). Ancora una volta, questi metodi sono davvero utili per mettere insieme sicurezza relativamente semplice del thread.
Se desideri essere ancora più sofisticato, penso che dovresti seriamente pensare a leggere Java Concurrency In Practice (se non lo hai già fatto). I blocchi di lettura e scrittura sono molto potenti senza aggiungere troppa complessità aggiuntiva.
Punchline: Utilizzando i metodi di sincronizzazione di base, è possibile sfruttare gran parte delle prestazioni abilitate dai moderni processori multi-core con thread-safety e senza molto overhead.
Il tuo esempio è scarsamente scelto, poiché String è immutabile e quindi apolide che è una rarità relativa. –
@ Kevin - grazie. Modificherà. –