JavaRush /Java Blogu /Random-AZ /Mövzu ilə Java-nı korlaya bilməzsiniz: VI hissə - maneəyə...
Viacheslav
Səviyyə

Mövzu ilə Java-nı korlaya bilməzsiniz: VI hissə - maneəyə!

Qrupda dərc edilmişdir

Giriş

Axınlar maraqlı bir şeydir. Əvvəlki təhlillərdə biz çox iş parçacığını həyata keçirmək üçün bəzi mövcud vasitələrə baxdıq. Gəlin görək daha nə maraqlı şeylər edə bilərik. Bu məqamda biz çox şey bilirik. Məsələn, “ Java-nı Mövzu ilə korlaya bilməzsiniz: I hissə - Mövzular ”dan biz bilirik ki, mövzu bir Mövzudur. Biz bilirik ki, ip hansısa vəzifəni yerinə yetirir. Tapşırığımızın işləyə bilməsini istəyiriksə ( run), onda mövzunun müəyyən olmasını göstərməliyik Runnable. Xatırlamaq üçün Tutorialspoint Java Online Compiler-dənMövzu ilə Java-nı korlaya bilməzsiniz: VI hissə - maneəyə!  - 1 istifadə edə bilərik :
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();
}
Kilid kimi bir anlayışımız olduğunu da bilirik. Bu barədə " Java-nı bir mövzu ilə korlaya bilməzsiniz: II hissə - Sinxronizasiya " məqaləsində oxuyuruq . Bir ip bir kilidi tuta bilər və sonra kilidi tutmağa çalışan başqa bir ip kilidin boşalmasını gözləmək məcburiyyətində qalacaq:
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();
	}
}
Düşünürəm ki, maraqlı olan başqa nə edə biləcəyimiz barədə danışmağın vaxtıdır.

Semaforlar

Neçə ipin eyni vaxtda işləyə biləcəyini idarə etmək üçün ən sadə vasitə semafordur. Dəmir yolunda olduğu kimi. Yaşıl işıq yanır - edə bilərsiniz. Qırmızı işıq yanır - gözləyirik. Semafordan nə gözləyirik? İcazələr. İngilis dilində icazə - icazə. İcazə almaq üçün ingilis dilində əldə ediləcək icazəni əldə etməlisiniz. İcazə artıq lazım olmadıqda, biz onu verməliyik, yəni azad etməliyik və ya ondan qurtulmalıyıq ki, bu da ingilis dilində buraxılacaq. Gəlin görək necə işləyir. Sinfi idxal etməliyik java.util.concurrent.Semaphore. Misal:
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);
}
Gördüyümüz kimi, ingilis sözlərini əzbərləyərək semaforun necə işlədiyini başa düşürük. Maraqlıdır ki, əsas şərt odur ki, semafor “hesabında” müsbət sayda icazə olmalıdır. Buna görə bir mənfi ilə başlaya bilərsiniz. Və 1-dən çox tələb edə (əldə edə bilərsiniz).

CountdownLatch

Növbəti mexanizmdir CountDownLatch. İngilis dilində Countdown geri sayımdır, Latch isə bolt və ya kiliddir. Yəni onu tərcümə etsək, bu, geri sayımı olan bir qapaqdır. Burada sinfin müvafiq idxalına ehtiyacımız var java.util.concurrent.CountDownLatch. Bu, hər kəsin start xəttinə toplaşdığı və hamı hazır olduqdan sonra icazənin verildiyi və hamının eyni vaxtda başladığı yarışa və ya yarışa bənzəyir. Misal:
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();
 	}
}
ingiliscə gözləmək - gözləmək. Yəni ilk biz danışırıq countDown. Google Tərcüməçinin dediyi kimi, geriyə sayma “rəqəmlərin tərs ardıcıllıqla sıfıra sayılması aktıdır”, yəni məqsədi sıfıra qədər saymaq olan geri sayım hərəkətini yerinə yetirməkdir. Və sonra deyirik await- yəni sayğacın dəyəri sıfır olana qədər gözləyin. Maraqlıdır ki, belə bir sayğac birdəfəlik istifadə olunur. JavaDoc-da deyildiyi kimi - "Mövzular bu şəkildə dəfələrlə geri sayılmalı olduqda, bunun əvəzinə CyclicBarrier istifadə edin", yəni təkrar istifadə edilə bilən saymağa ehtiyacınız varsa, başqa bir seçimdən istifadə etməlisiniz, buna CyclicBarrier.

Cyclic Barrier

Adından da göründüyü kimi, CyclicBarrierbu, tsiklik bir maneədir. Sinfi idxal etməliyik java.util.concurrent.CyclicBarrier. Bir misala baxaq:
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();
	}
}
Gördüyünüz kimi, ip icra olunur await, yəni gözləyir. Bu vəziyyətdə maneənin dəyəri azalır. berrier.isBroken()Geri sayım sıfıra çatdıqda maneə pozulmuş hesab olunur ( ). Baryeri sıfırlamaq üçün zəng etmək lazımdır berrier.reset(), hansı ki CountDownLatch.

dəyişdirici

Növbəti vasitə budur Exchanger. İngilis dilindən mübadilə mübadilə və ya mübadilə kimi tərcümə olunur. A Exchangerdəyişdiricidir, yəni mübadilə etdikləri bir şeydir. Sadə bir misala baxaq:
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();
}
Burada iki mövzu işə salırıq. Onların hər biri mübadilə metodunu yerinə yetirir və mübadilə metodunu başqa bir ipin də yerinə yetirməsini gözləyir. Beləliklə, mövzular keçən arqumentləri öz aralarında mübadilə edəcəklər. Maraqlı şey. O sizə heç nəyi xatırlatmır? Və xatırladır SynchronousQueueki, 'a'nın qəlbində yerləşir cachedThreadPool. Aydınlıq üçün bir nümunə:
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");
}
Nümunə göstərir ki, yeni başlıq açmaqla bu mövzu gözləmə rejiminə keçəcək, çünki növbə boş olacaq. Və sonra mainmövzu "Mesaj" mətnini növbəyə qoyacaq. Eyni zamanda, bu mətn elementini növbədən alana qədər tələb olunan vaxt dayanacaq. Bu mövzuda siz həmçinin oxuya bilərsiniz " SynchronousQueue Vs Exchanger ".

Fazer

Və nəhayət, ən şirin şey - Phaser. Sinfi idxal etməliyik java.util.concurrent.Phaser. Sadə bir misala baxaq:
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();
    }
Nümunə göstərir ki, Phaser'a istifadə edərkən, qeydiyyatların sayı maneəyə gələnlərin sayı ilə üst-üstə düşəndə ​​maneə pozulur. Daha çox məlumatı " New Phaser synchronizerPhaser " mərkəzindən məqalədə tapa bilərsiniz .

Nəticələr

Nümunələrdən göründüyü kimi, ipləri sinxronlaşdırmağın müxtəlif yolları var. Əvvəllər multithreading haqqında bir şey xatırlamağa çalışdım, ümid edirəm əvvəlki hissələr faydalı oldu. Onlar deyirlər ki, multithreading yolu "Java Concurrency in Practice" kitabından başlayır. 2006-cı ildə çıxmasına baxmayaraq, insanlar kitabın kifayət qədər fundamental olduğunu və hələ də bir zərbə olduğunu söyləyirlər. Məsələn, burada müzakirələri oxuya bilərsiniz: " Java Paralelliyi Təcrübədə hələ də etibarlıdırmı? ". Müzakirədən bağlantıları oxumaq da faydalıdır. Məsələn, " The Well-Grounded Java Developer " kitabına keçid var , orada " Fəsil 4. Müasir paralellik " ə diqqət yetirməyə dəyər . Eyni mövzuda başqa bir bütöv icmal var: “ Java 8-in erasında praktikada Java cocurrency hələ də aktualdırmı ?”. Mövzunu həqiqətən başa düşmək üçün başqa nə oxumalı olduğuna dair məsləhətlər də var. Bundan sonra siz " OCA OCP JavaSE 8 Proqramçı Təcrübə Testləri " kimi gözəl kitaba daha yaxından baxa bilərsiniz . Bizi ikinci hissə, yəni OCP maraqlandırır. Və "∫" da testlər var. Bu kitabda həm suallar, həm də izahatlarla cavablar var. Məsələn: Mövzu ilə Java-nı korlaya bilməzsiniz: VI hissə - maneəyə!  - 3Çoxları deməyə başlaya bilər ki, bu, üsulların növbəti əzbərlənməsidir. Bir tərəfdən, bəli. Digər tərəfdən, bu suala ExecutorServicebunun bir növ "təkmilləşdirmə" olduğunu xatırlamaqla cavab vermək olar Executor. Və Executorsadəcə olaraq mövzuların yaradılması metodunu gizlətmək üçün nəzərdə tutulmuşdur, lakin onları yerinə yetirməyin əsas yolu deyil, yəni yeni bir ipdə işləmək Runnable. Ona görə də execute(Callable)yox, çünki onlar sadəcə geri dönə bilən ExecutorServiceüsullar əlavə etdilər . Gördüyünüz kimi, metodların siyahısını yadda saxlaya bilərik, lakin dərslərin təbiətini bilsək, təxmin etmək daha asandır. Yaxşı, mövzu ilə bağlı bəzi əlavə materiallar: ExecutorsubmitFuture #Viaçeslav
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION