4 metodi per scrivere codice multi-thread in Java
Il multi-threading è un metodo per scrivere codice per eseguire attività in parallelo. Java ha avuto un eccellente supporto per la scrittura di codice multi-thread dagli albori di Java 1.0. I recenti miglioramenti apportati a Java hanno aumentato il modo in cui il codice può essere strutturato per incorporare il multi-threading nei programmi Java.
In questo articolo, confrontiamo alcune di queste opzioni in modo da poter giudicare meglio quale opzione utilizzare per il tuo prossimo progetto Java Love GitHub? 4 motivi per cui dovresti ospitare il tuo codice su BitBucket Love GitHub? 4 motivi per cui dovresti ospitare il tuo codice su BitBucket Devi pensare a dove intendi memorizzare il tuo codice. Probabilmente hai sentito parlare di GitHub. Non è sorprendente. GitHub è utilizzato da privati e aziende per ospitare codice, collaborare alla documentazione ... Per saperne di più t.
Metodo 1: estensione della classe Thread
Java fornisce a Filo classe che può essere estesa per implementare il correre() metodo. Questo metodo run () è dove si implementa l'attività. Quando si desidera avviare l'attività nel proprio thread, è possibile creare un'istanza di questa classe e richiamarla inizio() metodo. Questo avvia l'esecuzione del thread e viene eseguito fino al completamento (o termina in un'eccezione).
Ecco una semplice classe Thread che dorme solo per un intervallo specificato come un modo per simulare un'operazione di lunga durata.
MyThread di classe pubblica estende Thread private int sleepFor; public MyThread (int sleepFor) this.sleepFor = sleepFor; @Override public void run () System.out.printf ("[% s] thread starting \ n", Thread.currentThread (). ToString ()); prova Thread.sleep (this.sleepFor); catch (InterruptedException ex) System.out.printf ("[% s] thread terminando \ n", Thread.currentThread (). toString ());
Crea un'istanza di questa classe Thread dandogli il numero di millisecondi per dormire.
MyThread worker = new MyThread (sleepFor);
Avvia l'esecuzione di questo thread di lavoro richiamando il suo metodo start (). Questo metodo restituisce il controllo immediatamente al chiamante, senza attendere il termine del thread.
worker.start (); System.out.printf ("[% s] main thread \ n", Thread.currentThread (). ToString ());
Ed ecco l'output dall'esecuzione di questo codice. Indica che la diagnostica del thread principale viene stampata prima dell'esecuzione del thread di lavoro.
[Thread [main, 5, main]] thread principale [Thread [Thread-0,5, main]] thread starting [Thread [Thread-0,5, main]] terminando il thread
Poiché non ci sono più istruzioni dopo l'avvio del thread di lavoro, il thread principale attende il termine del thread di lavoro prima che il programma venga chiuso. Ciò consente al thread di lavoro di completare l'attività.
Metodo 2: utilizzo di un'istanza di thread con un Runnable
Java fornisce anche un'interfaccia chiamata Runnable che può essere implementato da una classe worker per eseguire l'attività nella sua correre() metodo. Questo è un modo alternativo di creare una classe operaia piuttosto che estendere il Filo classe (descritta sopra).
Ecco l'implementazione della classe worker che ora implementa Runnable invece di estendere Thread.
MyThread2 di public class implementa Runnable // same as above
Il vantaggio di implementare l'interfaccia Runnable invece di estendere la classe Thread è che la classe worker può ora estendere una classe specifica del dominio all'interno di una gerarchia di classi.
Cosa significa questo?
Diciamo, per esempio, hai un Frutta classe che implementa alcune caratteristiche generiche dei frutti. Ora vuoi implementare a Papaia classe che specializza alcune caratteristiche della frutta. Puoi farlo avendo il Papaia classe estendere il Frutta classe.
frutta di classe pubblica // frutta specifica qui classe pubblica Papaya estende frutta // comportamento override specifico per papaya qui
Supponiamo ora di avere un compito lungo che Papaya deve supportare, che può essere eseguito in un thread separato. Questo caso può essere gestito avendo la classe di Papaya implementare Runnable e fornire il metodo run () in cui viene eseguita questa attività.
public class Papaya estende Fruit implementa Runnable // override comportamento specifico per papaya qui @Override public void run () // attività che richiede tempo qui.
Per dare il via al thread worker, si crea un'istanza della classe worker e la si consegna a un'istanza Thread al momento della creazione. Quando viene richiamato il metodo start () del Thread, l'attività viene eseguita in un thread separato.
Papaya papaya = new Papaya (); // imposta le proprietà e invoca i metodi papaya qui. Thread thread = new Thread (papaya); Thread.start ();
E questo è un breve riassunto su come usare un Runnable per implementare un'attività in esecuzione all'interno di un thread.
Metodo 3: Esegui un Runnable con ExecutorService
A partire dalla versione 1.5, Java fornisce un ExecutorService come un nuovo paradigma per creare e gestire i thread all'interno di un programma. Generalizza il concetto di esecuzione del thread estraendo la creazione di thread.
Questo perché è possibile eseguire le attività in un pool di thread con la stessa facilità con cui si utilizza un thread separato per ogni attività. Ciò consente al programma di tracciare e gestire il numero di thread utilizzati per le attività di lavoro.
Supponiamo che tu abbia 100 compiti di lavoro in attesa di essere eseguiti. Se inizi un thread per worker (come presentato sopra), avresti 100 thread nel tuo programma che potrebbero portare a colli di bottiglia in altre parti del programma. Invece, se si utilizza un pool di thread con, ad esempio, 10 thread pre-allocati, le 100 attività verranno eseguite da questi thread uno dopo l'altro in modo che il programma non sia affamato di risorse. Inoltre, questi thread del pool di thread possono essere configurati in modo che restino in attesa per eseguire attività aggiuntive.
Un ExecutorService accetta un Runnable compito (spiegato sopra) ed esegue l'attività in un momento opportuno. Il Sottoscrivi() metodo, che accetta l'attività Runnable, restituisce un'istanza di una classe chiamata Futuro, che consente al chiamante di tenere traccia dello stato dell'attività. In particolare, il ottenere() metodo consente al chiamante di attendere il completamento dell'attività (e fornisce il codice di ritorno, se presente).
Nell'esempio seguente, creiamo un ExecutorService usando il metodo statico newSingleThreadExecutor (), che come indica il nome, crea un singolo thread per l'esecuzione delle attività. Se vengono eseguite più attività mentre è in esecuzione un'attività, ExecutorService mette in coda queste attività per l'esecuzione successiva.
L'implementazione Runnable che usiamo qui è la stessa descritta sopra.
ExecutorService esvc = Executors.newSingleThreadExecutor (); Runnable worker = new MyThread2 (sleepFor); Futuro> futuro = esvc.submit (lavoratore); System.out.printf ("[% s] main thread \ n", Thread.currentThread (). ToString ()); future.get (); esvc.shutdown ();
Si noti che un ExecutorService deve essere correttamente spento quando non è più necessario per ulteriori invii di attività.
Metodo 4: un Callable utilizzato con ExecutorService
A partire dalla versione 1.5, Java ha introdotto una nuova interfaccia chiamata callable. È simile alla precedente interfaccia Runnable con la differenza che il metodo di esecuzione (chiamato chiamata() invece di correre()) può restituire un valore. Inoltre, può anche dichiarare che a Eccezione può essere lanciato.
Un ExecutorService può anche accettare attività implementate come callable e restituisce a Futuro con il valore restituito dal metodo al completamento.
Ecco un esempio Mango classe che estende il Frutta classe definita in precedenza e implementa il callable interfaccia. Un'attività costosa e dispendiosa in termini di tempo viene eseguita all'interno di chiamata() metodo.
public class Mango estende Fruit implementa Callable public Integer call () // I calcoli costosi qui restituiscono nuovo Integer (0);
Ed ecco il codice per inviare un'istanza della classe a un ExecutorService. Il codice sottostante attende inoltre che l'attività venga completata e stampi il suo valore di ritorno.
ExecutorService esvc = Executors.newSingleThreadExecutor (); MyCallable worker = new MyCallable (sleepFor); Futuro futuro = esvc.submit (lavoratore); System.out.printf ("[% s] main thread \ n", Thread.currentThread (). ToString ()); System.out.println ("Task restituito:" + future.get ()); esvc.shutdown ();
Cosa preferisci?
In questo articolo, abbiamo imparato alcuni metodi per scrivere codice multi-thread in Java. Questi includono:
- Estendere il Filo la classe è la più basilare ed è stata disponibile da Java 1.0.
- Se hai una classe che deve estendere qualche altra classe in una gerarchia di classi, allora puoi implementare la Runnable interfaccia.
- Una struttura più moderna per la creazione di thread è il ExecutorService che può accettare un'istanza Runnable come compito da eseguire. Il vantaggio di questo metodo è che è possibile utilizzare un pool di thread per l'esecuzione dell'attività. Un pool di thread aiuta nella conservazione delle risorse riutilizzando i thread.
- Infine, puoi anche creare un'attività implementando il callable interfaccia e invio dell'attività a un ExecutorService.
Quale di queste opzioni pensi che userai nel tuo prossimo progetto? Fateci sapere nei commenti qui sotto.
Scopri di più su: Java.