JavaRush /Java Blog /Random-TL /Hindi mo masisira ang Java gamit ang isang Thread: Part V...

Hindi mo masisira ang Java gamit ang isang Thread: Part VI - Sa barrier!

Nai-publish sa grupo

Panimula

Ang mga stream ay isang kawili-wiling bagay. Sa mga nakaraang pagsusuri, tiningnan namin ang ilan sa mga magagamit na tool para sa pagpapatupad ng multithreading. Tingnan natin kung ano pa ang mga kawili-wiling bagay na maaari nating gawin. Sa puntong ito marami tayong alam. Halimbawa, mula sa “ You Can't Spoil Java with a Thread: Part I - Threads, " alam namin na ang isang thread ay isang Thread. Alam namin na ang isang thread ay nagsasagawa ng ilang gawain. Kung gusto nating tumakbo ang ating gawain ( run), dapat nating tukuyin ang thread upang maging tiyak Runnable. Hindi mo masisira ang Java gamit ang isang Thread: Part VI - Sa barrier!  - 1Upang matandaan, maaari naming gamitin ang Tutorialspoint Java Online 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();
}
Alam din natin na mayroon tayong ganitong konsepto bilang lock. Nabasa namin ang tungkol dito sa " You Can't Spoil Java with a Thread: Part II - Synchronization ." Maaaring sakupin ng isang thread ang isang lock at pagkatapos ay ang isa pang thread na sumusubok na sakupin ang kandado ay mapipilitang maghintay para maging libre ang lock:
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();
	}
}
Sa tingin ko oras na para pag-usapan kung ano pa ang magagawa natin na kawili-wili.

Mga semaphore

Ang pinakasimpleng paraan ng pagkontrol kung gaano karaming mga thread ang maaaring gumana nang sabay-sabay ay isang semaphore. Parang sa riles. Naka-on ang berdeng ilaw - maaari mo. Bukas ang pulang ilaw - naghihintay kami. Ano ang inaasahan natin mula sa isang semaphore? Mga Pahintulot. Pahintulot sa Ingles - permit. Upang makakuha ng pahintulot, kailangan mong makuha ito, na sa Ingles ay makukuha. At kapag hindi na kailangan ng permiso, kailangan na natin itong ibigay, ibig sabihin, bitawan o tanggalin, na sa English ay ilalabas. Tingnan natin kung paano ito gumagana. Kakailanganin nating i-import ang klase java.util.concurrent.Semaphore. Halimbawa:
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);
}
Tulad ng nakikita natin, na naisaulo ang mga salitang Ingles, naiintindihan natin kung paano gumagana ang semaphore. Kapansin-pansin, ang pangunahing kondisyon ay ang semaphore na "account" ay dapat na may positibong bilang ng mga permit. Samakatuwid, maaari mong simulan ito ng isang minus. At maaari kang humiling (makakuha) ng higit sa 1.

CountDownLatch

Ang susunod na mekanismo ay CountDownLatch. Ang CountDown sa English ay isang countdown, at ang Latch ay isang bolt o latch. Ibig sabihin, kung isasalin natin ito, ito ay isang latch na may countdown. Dito kailangan natin ang naaangkop na pag-import ng klase java.util.concurrent.CountDownLatch. Ito ay parang karera o karera kung saan lahat ay nagtitipon sa panimulang linya at kapag handa na ang lahat, binibigyan ng pahintulot at lahat ay nagsisimula nang sabay-sabay. Halimbawa:
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();
 	}
}
maghintay sa English - to expect. Ibig sabihin, mag-usap muna kami countDown. Gaya ng sabi ng Google Translator, ang count down ay "isang pagkilos ng pagbibilang ng mga numero sa reverse order sa zero," ibig sabihin, magsagawa ng countdown action, ang layunin nito ay magbilang hanggang zero. At pagkatapos ay sinasabi namin await- iyon ay, maghintay hanggang ang counter value ay maging zero. Ito ay kagiliw-giliw na ang naturang counter ay disposable. Tulad ng sinabi sa JavaDoc - "Kapag ang mga thread ay dapat na paulit-ulit na bilangin pababa sa paraang ito, sa halip ay gumamit ng isang CyclicBarrier", iyon ay, kung kailangan mo ng reusable counting, kailangan mong gumamit ng isa pang opsyon, na tinatawag na CyclicBarrier.

CyclicBarrier

Gaya ng ipinahihiwatig ng pangalan, CyclicBarrierito ay isang paikot na hadlang. Kakailanganin nating i-import ang klase java.util.concurrent.CyclicBarrier. Tingnan natin ang isang halimbawa:
public static void main(String[] args) throws InterruptedException {
	Runnable action = () -> System.out.println("На старт!");
	CyclicBarrier berrier = new CyclicBarrier(3, action);
	Runnable task = () -> {
		try {
			berrier.await();
			System.out.println("Finished");
		} catch (BrokenBarrierException | InterruptedException e) {
			e.printStackTrace();
		}
	};
	System.out.println("Limit: " + berrier.getParties());
	for (int i = 0; i < 3; i++) {
		new Thread(task).start();
	}
}
Tulad ng nakikita mo, ang thread ay nagpapatupad await, iyon ay, naghihintay. Sa kasong ito, bumababa ang halaga ng hadlang. Ang hadlang ay itinuturing na sira ( berrier.isBroken()) kapag ang countdown ay umabot sa zero. Upang i-reset ang hadlang, kailangan mong tawagan ang berrier.reset(), na nawawala sa CountDownLatch.

Exchanger

Ang susunod na lunas ay Exchanger. Ang palitan mula sa Ingles ay isinalin bilang exchange o exchange. Ang A Exchangeray isang exchanger, iyon ay, isang bagay kung saan sila nakikipagpalitan. Tingnan natin ang isang simpleng halimbawa:
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() + " обменялся с " + withThreadName);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	};
	new Thread(task).start();
	new Thread(task).start();
}
Dito naglulunsad kami ng dalawang thread. Ang bawat isa sa kanila ay nagpapatupad ng paraan ng palitan at naghihintay para sa isa pang thread na isakatuparan din ang paraan ng palitan. Kaya, ang mga thread ay magpapalitan ng mga naipasa na argumento sa kanilang mga sarili. Kawili-wiling bagay. Wala ba siyang naaalala sa iyo? At pinaalalahanan niya si SynchronousQueue, na nasa puso ng cachedThreadPool'a. Para sa kalinawan, narito ang isang halimbawa:
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");
}
Ipinapakita ng halimbawa na sa pamamagitan ng paglulunsad ng bagong thread, mapupunta ang thread na ito sa waiting mode, dahil mawawalan ng laman ang pila. At pagkatapos mainay i-queue ng thread ang text na "Mensahe". Kasabay nito, hihinto ito sa kinakailangang oras hanggang sa matanggap nito ang elemento ng teksto mula sa pila. Sa paksang ito maaari mo ring basahin ang " SynchronousQueue Vs Exchanger ".

Phaser

At sa wakas, ang pinakamatamis na bagay - Phaser. Kakailanganin nating i-import ang klase java.util.concurrent.Phaser. Tingnan natin ang isang simpleng halimbawa:
public static void main(String[] args) throws InterruptedException {
        Phaser phaser = new Phaser();
        // Вызывая метод register, мы регистрируем текущий поток (main) How участника
        phaser.register();
        System.out.println("Phasecount is " + phaser.getPhase());
        testPhaser(phaser);
        testPhaser(phaser);
        testPhaser(phaser);
        // Через 3 секунды прибываем к барьеру и снимаемся регистрацию. Кол-во прибывших = кол-во регистраций = пуск
        Thread.sleep(3000);
        phaser.arriveAndDeregister();
        System.out.println("Phasecount is " + phaser.getPhase());
    }

    private static void testPhaser(final Phaser phaser) {
        // Говорим, что будет +1 участник на Phaser
        phaser.register();
        // Запускаем новый поток
        new Thread(() -> {
            String name = Thread.currentThread().getName();
            System.out.println(name + " arrived");
            phaser.arriveAndAwaitAdvance(); //threads register arrival to the phaser.
            System.out.println(name + " after passing barrier");
        }).start();
    }
Ang halimbawa ay nagpapakita na ang hadlang, kapag gumagamit ng Phaser'a, ay nasira kapag ang bilang ng mga pagpaparehistro ay tumutugma sa bilang ng mga dumating sa hadlang. Maaari mong malaman ang higit pa Phasersa artikulo mula sa hub na " New Phaser synchronizer ".

Mga resulta

Tulad ng nakikita mo mula sa mga halimbawa, may iba't ibang paraan upang i-synchronize ang mga thread. Kanina sinubukan kong alalahanin ang tungkol sa multithreading, sana ay kapaki-pakinabang ang mga naunang bahagi. Sinasabi nila na ang landas sa multithreading ay nagsisimula sa aklat na "Java Concurrency in Practice". Bagama't ito ay lumabas noong 2006, ang mga tao ay tumugon na ang aklat ay napaka-pangunahing at pa rin pack ng isang suntok. Halimbawa, maaari mong basahin ang mga talakayan dito: " Wasto pa rin ba ang Java Concurrency In Practice? ". Nakatutulong din na basahin ang mga link mula sa talakayan. Halimbawa, mayroong isang link sa aklat na " The Well-Grounded Java Developer ", kung saan ito ay nagkakahalaga ng pagbibigay pansin sa " Kabanata 4. Modern concurrency ". May isa pang buong pagsusuri sa parehong paksa: " May kaugnayan pa ba ang Java cocurrency sa pracitce sa panahon ng java 8 ". Mayroon din itong mga tip kung ano pa ang dapat mong basahin upang talagang maunawaan ang paksa. Pagkatapos nito, maaari mong tingnang mabuti ang napakagandang aklat gaya ng " OCA OCP JavaSE 8 Programmer Practice Tests ". Interesado kami sa pangalawang bahagi, iyon ay, OCP. At may mga pagsubok sa "∫". Ang aklat na ito ay naglalaman ng parehong mga tanong at sagot na may mga paliwanag. Halimbawa: Hindi mo masisira ang Java gamit ang isang Thread: Part VI - Sa barrier!  - 3Marami ang maaaring magsimulang magsabi na isa lamang itong pagsasaulo ng mga pamamaraan. Sa isang banda, oo. Sa kabilang banda, masasagot ang tanong na ito sa pamamagitan ng pag-alala na ExecutorServiceito ay isang uri ng "pag-upgrade" Executor. At Executorito ay inilaan lamang upang itago ang paraan ng paglikha ng mga thread, ngunit hindi ang pangunahing paraan ng pagpapatupad ng mga ito, iyon ay, tumatakbo sa isang bagong thread Runnable. Samakatuwid, execute(Callable)hindi, dahil nagdagdag lamang sila ng mga pamamaraan ExecutorServicena maaaring bumalik . Tulad ng nakikita mo, maaari naming kabisaduhin ang isang listahan ng mga pamamaraan, ngunit mas madaling hulaan kung alam namin ang likas na katangian ng mga klase mismo. Well, ilang karagdagang mga materyales sa paksa: ExecutorsubmitFuture #Viacheslav
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION