CodeGym /Java-blogg /Tilfeldig /Bedre sammen: Java og Thread-klassen. Del VI – Fyr vekk!
John Squirrels
Nivå
San Francisco

Bedre sammen: Java og Thread-klassen. Del VI – Fyr vekk!

Publisert i gruppen

Introduksjon

Tråder er en interessant ting. I tidligere anmeldelser har vi sett på noen av de tilgjengelige verktøyene for implementering av multithreading. La oss se hvilke andre interessante ting vi kan gjøre. På dette tidspunktet vet vi mye. For eksempel, fra " Better together: Java and the Thread class. Part I — Threads of execution " vet vi at Thread-klassen representerer en tråd av execution. Vi vet at en tråd utfører en oppgave. Skal vi at oppgavene våre skal kunne run, så må vi merke tråden med Runnable. Bedre sammen: Java og Thread-klassen.  Del VI – Fyr vekk!  - 1For å huske, kan vi bruke Tutorialspoint Online Java Compiler :

public static void main(String[] args){
	Runnable task = () -> {
 		Thread thread = Thread.currentThread();
		System.out.println("Hello from " + thread.getName());
	};
	Thread thread = new Thread(task);
	thread.start();
}
Vi vet også at vi har noe som heter lås. Vi lærte om dette i " Better together: Java and the Thread class. Part II — Synchronization . Hvis en tråd får en lås, vil en annen tråd som prøver å få tak i låsen bli tvunget til å vente på at låsen frigjøres:

import java.util.concurrent.locks.*;

public class HelloWorld{
	public static void main(String []args){
		Lock lock = new ReentrantLock();
		Runnable task = () -> {
			lock.lock();
			Thread thread = Thread.currentThread();
			System.out.println("Hello from " + thread.getName());
			lock.unlock();
		};
		Thread thread = new Thread(task);
		thread.start();
	}
}
Jeg tror det er på tide å snakke om hvilke andre interessante ting vi kan gjøre.

Semaforer

Den enkleste måten å kontrollere hvor mange tråder som kan kjøres samtidig, er en semafor. Det er som et jernbanesignal. Grønt betyr fortsett. Rød betyr vent. Vent på hva fra semaforen? Adgang. For å få tilgang må vi skaffe den. Og når tilgang ikke lenger er nødvendig, må vi gi den bort eller frigi den. La oss se hvordan dette fungerer. Vi må importere java.util.concurrent.Semaphoreklassen. Eksempel:

public static void main(String[] args) throws InterruptedException {
	Semaphore semaphore = new Semaphore(0);
	Runnable task = () -> {
		try {
			semaphore.acquire();
			System.out.println("Finished");
			semaphore.release();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	};
	new Thread(task).start();
	Thread.sleep(5000);
	semaphore.release(1);
}
Som du kan se, hjelper disse operasjonene (anskaffe og frigi) oss å forstå hvordan en semafor fungerer. Det viktigste er at hvis vi skal få tilgang, så må semaforen ha et positivt antall tillatelser. Denne tellingen kan initialiseres til et negativt tall. Og vi kan be om (anskaffe) mer enn 1 tillatelse.

CountDownLatch

Den neste mekanismen er CountDownLatch. Ikke overraskende er dette en lås med nedtelling. Her trenger vi den passende importerklæringen for java.util.concurrent.CountDownLatchklassen. Det er som et fotløp, hvor alle samles på startstreken. Og når alle er klare, får alle startsignalet samtidig og starter samtidig. Eksempel:

public static void main(String[] args) {
	CountDownLatch countDownLatch = new CountDownLatch(3);
	Runnable task = () -> {
		try {
			countDownLatch.countDown();
			System.out.println("Countdown: " + countDownLatch.getCount());
			countDownLatch.await();
			System.out.println("Finished");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	};
	for (int i = 0; i < 3; i++) {
		new Thread(task).start();
 	}
}
Først forteller vi låsen til countDown(). Google definerer nedtelling som "en handling med å telle tall i omvendt rekkefølge til null". Og så forteller vi sperren til await(), dvs. vent til telleren blir null. Interessant nok er dette en engangsteller. Java-dokumentasjonen sier: "Når tråder gjentatte ganger må telle ned på denne måten, bruk i stedet en CyclicBarrier". Med andre ord, hvis du trenger en gjenbrukbar teller, trenger du et annet alternativ: CyclicBarrier.

CyclicBarrier

Som navnet tilsier, CyclicBarrierer en "gjenbrukbar" barriere. Vi må importere java.util.concurrent.CyclicBarrierklassen. La oss se på et eksempel:

public static void main(String[] args) throws InterruptedException {
	Runnable action = () -> System.out.println("On your mark!");
	CyclicBarrier barrier = new CyclicBarrier(3, action);
	Runnable task = () -> {
		try {
			barrier.await();
			System.out.println("Finished");
		} catch (BrokenBarrierException | InterruptedException e) {
			e.printStackTrace();
		}
	};
	System.out.println("Limit: " + barrier.getParties());
	for (int i = 0; i < 3; i++) {
		new Thread(task).start();
	}
}
Som du ser kjører tråden awaitmetoden, dvs. den venter. I dette tilfellet synker barriereverdien. Barrieren anses som brutt ( barrier.isBroken()) når nedtellingen når null. For å tilbakestille barrieren, må du ringe reset()metoden, som CountDownLatchikke har.

Utveksler

Den neste mekanismen er Exchanger. I denne sammenhengen er en Exchange et synkroniseringspunkt hvor ting endres byttes eller byttes. Som du forventer, Exchangerer an en klasse som utfører en utveksling eller bytte. La oss se på det enkleste eksemplet:

public static void main(String[] args) {
	Exchanger<String> exchanger = new Exchanger<>();
	Runnable task = () -> {
		try {
			Thread thread = Thread.currentThread();
			String withThreadName = exchanger.exchange(thread.getName());
			System.out.println(thread.getName() + " exchanged with " + withThreadName);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	};
	new Thread(task).start();
	new Thread(task).start();
}
Her starter vi to tråder. Hver av dem kjører utvekslingsmetoden og venter på at den andre tråden også kjører utvekslingsmetoden. Ved å gjøre det, utveksler trådene de beståtte argumentene. Interessant. Minner det deg ikke om noe? Det minner om SynchronousQueue, som ligger i hjertet av CachedThreadPool. For klarhetens skyld, her er et eksempel:

public static void main(String[] args) throws InterruptedException {
	SynchronousQueue<String> queue = new SynchronousQueue<>();
	Runnable task = () -> {
		try {
			System.out.println(queue.take());
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	};
	new Thread(task).start();
	queue.put("Message");
}
Eksemplet viser at når en ny tråd startes, vil den vente, fordi køen vil være tom. Og så setter hovedtråden "Message"-strengen inn i køen. Dessuten vil den også stoppe til denne strengen er mottatt fra køen. Du kan også lese " SynchronousQueue vs Exchanger " for å finne mer om dette emnet.

Phaser

Vi har lagret det beste til sist — Phaser. Vi må importere java.util.concurrent.Phaserklassen. La oss se på et enkelt eksempel:

public static void main(String[] args) throws InterruptedException {
        Phaser phaser = new Phaser();
        // By calling the register method, we register the current (main) thread as a party
        phaser.register();
        System.out.println("Phasecount is " + phaser.getPhase());
        testPhaser(phaser);
        testPhaser(phaser);
        testPhaser(phaser);
        // After 3 seconds, we arrive at the barrier and deregister. Number of arrivals = number of registrations = start
        Thread.sleep(3000);
        phaser.arriveAndDeregister();
        System.out.println("Phasecount is " + phaser.getPhase());
    }

    private static void testPhaser(final Phaser phaser) {
        // We indicate that there will be a +1 party on the Phaser
        phaser.register();
        // Start a new thread
        new Thread(() -> {
            String name = Thread.currentThread().getName();
            System.out.println(name + " arrived");
            phaser.arriveAndAwaitAdvance(); // The threads register arrival at the phaser.
            System.out.println(name + " after passing barrier");
        }).start();
    }
Eksempelet illustrerer at ved bruk Phaserryker bommen når antall registreringer stemmer med antall ankomster til bommen. Du kan bli mer kjent med Phaserved å lese denne GeeksforGeeks-artikkelen .

Sammendrag

Som du kan se av disse eksemplene, er det ulike måter å synkronisere tråder på. Tidligere prøvde jeg å huske aspekter ved multithreading. Jeg håper de tidligere delene i denne serien var nyttige. Noen sier at veien til multithreading begynner med boken "Java Concurrency in Practice". Selv om den ble utgitt i 2006, sier folk at boken er ganske grunnleggende og fortsatt aktuell i dag. Du kan for eksempel lese diskusjonen her: Er «Java Concurrency In Practice» fortsatt gyldig? . Det er også nyttig å lese lenkene i diskusjonen. For eksempel er det en lenke til boken The Well-Grounded Java Developer , og vi vil spesielt nevne kapittel 4. Modern concurrency . Det er også en hel anmeldelse om dette emnet:Er "Java-samtidighet i praksis" fortsatt gyldig i Java 8-epoken? Denne artikkelen gir også forslag om hva annet du bør lese for å virkelig forstå dette emnet. Etter det kan du ta en titt på en flott bok som OCA/OCP Java SE 8 Programmer Practice Tests . Vi er interessert i det andre akronymet: OCP (Oracle Certified Professional). Du finner tester i "Chapter 20: Java Concurrency". Denne boken har både spørsmål og svar med forklaringer. For eksempel: Bedre sammen: Java og Thread-klassen.  Del VI – Fyr vekk!  - 3Mange begynner kanskje å si at dette spørsmålet er nok et eksempel på memorering av metoder. På den ene siden, ja. På den annen side kan du svare på dette spørsmålet ved å huske at det ExecutorServiceer en slags "oppgradering" av Executor. OgExecutorer ment å bare skjule måten tråder lages på, men det er ikke hovedmåten å utføre dem på, det vil si å starte et Runnableobjekt på en ny tråd. Det er derfor det ikke er noe execute(Callable)- fordi i legger ExecutorServiceden Executorganske enkelt til submit()metoder som kan returnere et Futureobjekt. Selvfølgelig kan vi huske en liste over metoder, men det er mye lettere å lage svaret vårt basert på vår kunnskap om klassenes natur. Og her er noen tilleggsmaterialer om emnet: Bedre sammen: Java og Thread-klassen. Del I — Tråder av utførelse Bedre sammen: Java og trådklassen. Del II — Synkronisering Bedre sammen: Java og Thread-klassen. Del III — Interaksjon Bedre sammen: Java og Thread-klassen. Del IV — Callable, Future og friends Bedre sammen: Java og Thread-klassen. Del V — Utfører, ThreadPool, Fork/Join
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION