Comportamento del metodo statico in ambiente multi-thread in java


114

C'è una semplice domanda stupida che mi infastidisce e mi fa venire in mente diversi argomenti. Voglio buttare via tutti i dubbi sulle domande sottostanti.

class Clstest{

    public static String testStaticMethod(String inFileStr) {

        // section 0

        // section 1

        // do something with inFileStr

        // section 2

        // section 3

        return inFileStr;

    }

}

Supponiamo che ci siano cinque thread a cui ciascuno sta eseguendo una chiamata Clstest.testStaticMethod("arg-n")contemporaneamente.

Il thread 1 chiama Clstest.testStaticMethod("arg-1").

Quando il thread 1 è nella sezione 1, il thread 2 chiama Clstest.testStaticMethod("arg-2").

Quindi cosa accadrà al thread 1? Andrà in stato di sonno?

Quando il thread 1 ha avuto la possibilità, riprenderà l'esecuzione dalla sezione 1 in cui era stata sospesa?

Come succede quando ce n'è uno Clstest.testStaticMethode lo stesso Clstest.testStaticMethodè condiviso tra tutti e cinque i thread?

C'è qualche possibilità di scambiare l' inFileStrinvio da più thread?


Quale lingua stai prendendo di mira?
ΩmegaMan

3
@ OmegaMan: è java
namalfernandolk,

Risposte:


192

La risposta di Hans Passant è buona. Ma ho pensato di provare a spiegare a un livello leggermente più semplice per chiunque si imbattesse in questo ed è nuovo di Java. Ecco qui..

La memoria in java è suddivisa in due tipi: l'heap e gli stack. L'heap è dove vivono tutti gli oggetti e gli stack sono dove i thread svolgono il loro lavoro. Ogni thread ha il proprio stack e non può accedere agli stack degli altri. Ogni thread ha anche un puntatore nel codice che punta al bit di codice attualmente in esecuzione.

Quando un thread inizia a eseguire un nuovo metodo, salva gli argomenti e le variabili locali in quel metodo sul proprio stack. Alcuni di questi valori potrebbero essere puntatori a oggetti nell'heap. Se due thread eseguono lo stesso metodo contemporaneamente, entrambi avranno i loro puntatori di codice che puntano a quel metodo e avranno le proprie copie di argomenti e variabili locali nei loro stack. Interferiranno tra loro solo se le cose sulle loro pile puntano agli stessi oggetti sul mucchio. In tal caso potrebbero accadere cose di ogni genere. Ma come sottolinea Hans, le stringhe sono immutabili (non possono essere modificate) quindi siamo al sicuro se questo è l'unico oggetto "condiviso".

Così tanti thread possono eseguire lo stesso metodo. Potrebbero non essere in esecuzione contemporaneamente: dipende dal numero di core presenti sulla macchina poiché JVM associa i thread Java ai thread del sistema operativo, che sono programmati sui thread hardware. Hai quindi poco controllo sul modo in cui questi thread si alternano senza utilizzare complessi meccanismi di sincronizzazione .

Nota che dormire è qualcosa che un thread fa a se stesso.


3
Quindi, nell'ambiente del processore multi-core potrebbero esserci più thread che eseguono lo stesso codice nello stesso momento, non è vero? E nell'ambiente con un solo processore c'è un solo thread in esecuzione in un dato momento. (più thread condividono il tempo tra di loro.) Quindi, quando il thread schedular dà la possibilità dal thread corrente di excuting (A) al thread (B), come riprende il thread (A) da dove era stato messo in pausa? Voglio dire come fa a conoscere il punto di ripresa? È a causa di "Ogni thread ha anche un puntatore nel codice che punta al bit di codice attualmente in esecuzione?" come hai detto?
namalfernandolk,

6
Ce l'hai. Solo per chiarire alcuni punti: in primo luogo, il modo in cui i thread sono pianificati è al di fuori del controllo di Java. Sto parlando di Sun's Hotspot JVM qui. La JVM mappa un thread Java su un thread del sistema operativo e il sistema operativo decide quali thread eseguire. Come dici tu, su una macchina single core il sistema operativo può essere eseguito solo uno alla volta, ma in una macchina multicore può eseguirne più di uno alla volta. In secondo luogo, un thread non è realmente consapevole di quando viene messo in pausa, le uniche informazioni che ha sono il suo puntatore al programma (il puntatore nel codice) e lo stack, che vengono salvati e ripristinati esattamente come erano.
selig

Quindi, l'interferenza tra thread si verifica quando i thread utilizzano variabili al di fuori del loro ambito locale e, ad esempio, un thread aggiorna il valore della variabile prima che un altro thread estragga quella variabile (o il puntatore alla variabile) sul proprio stack? È una giusta comprensione?
hariszhr

2
Per essere un po 'più precisi ... l'interferenza può accadere e può accadere ma non necessariamente accadrà ... quando i thread condividono cose sull'heap (non locale). Esistono diversi modi in cui possono verificarsi interferenze che dipendono dalle dipendenze tra le diverse parti del codice. Non sono sicuro del tuo esempio perché mancano alcuni dettagli. Forse ti riferisci a un potenziale problema in cui i thread A e B leggono entrambi un valore condiviso e quindi lo aggiornano entrambi in base al valore letto. Questa è una corsa ai dati.
selig

1
@selig se ho una classe con solo metodi di istanza per es: una classe di servizio ed è singleton, non devo preoccuparmi di più thread che eseguono i metodi di istanza alla volta poiché la classe di servizio non contiene alcuno stato in cui state è presente solo se la classe ha variabili di istanza. La mia comprensione è corretta?
Yug Singh

67

Andrà in stato di sonno?

No, l'esecuzione di un thread non influisce sugli altri thread, a condizione che non si sincronizzino intenzionalmente tra loro. Se hai più di un core del processore, come tutte le macchine recenti, è probabile che quei thread vengano eseguiti esattamente allo stesso tempo. Ciò diventa un po 'meno probabile quando avvii 5 thread poiché la tua macchina potrebbe non avere abbastanza core. Il sistema operativo è costretto a scegliere tra di loro, dando loro un po 'di tempo per funzionare. Il lavoro dello scheduler dei thread. Un thread non sarà quindi in uno stato di "sospensione", viene semplicemente messo in pausa e in attesa che lo scheduler del thread gli dia la possibilità di essere eseguito. Riprenderà dal punto in cui era stato interrotto dallo scheduler.

C'è la possibilità di scambiare l'inFileStr inviato da più thread?

Non esiste tale possibilità, i thread hanno il proprio stack quindi qualsiasi argomento del metodo e variabile locale sarà univoco per ogni thread. L'utilizzo di una stringa garantisce inoltre che questi thread non possano interferire tra loro poiché le stringhe sono immutabili.

Non esiste tale garanzia se l'argomento è un riferimento a un altro tipo di oggetto mutabile. O se il metodo stesso utilizza variabili statiche o riferimenti a oggetti sull'heap. La sincronizzazione è necessaria quando un thread modifica l'oggetto e un altro thread lo legge. La parola chiave lock nel linguaggio C # è il modo standard per implementare tale sincronizzazione richiesta. Il fatto che il metodo sia statico non significa che tale sincronizzazione non sia mai richiesta. Solo meno probabile poiché non devi preoccuparti che i thread accedano allo stesso oggetto (condividendo questo ).


3
Oops, non ho mai visto il tag [java]. Abbastanza vicino.
Hans Passant,

Ho dimenticato di aggiungere quando è stato pubblicato. Colpa mia. :). Comunque grazie per la risposta. È stato molto utile.
namalfernandolk,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.