JavaRush /Java блогы /Random-KK /Сіз Java тілін жіппен бүлдіре алмайсыз: VI бөлім - Кедерг...
Viacheslav
Деңгей

Сіз Java тілін жіппен бүлдіре алмайсыз: VI бөлім - Кедергіге!

Топта жарияланған

Кіріспе

Ағындар - бұл қызықты нәрсе. Алдыңғы шолуларда біз көп ағынды енгізуге арналған кейбір қолжетімді құралдарды қарастырдық. Тағы қандай қызықты нәрселер жасай алатынымызды көрейік. Осы кезде біз көп нәрсені білеміз. Мысалы, « Java-ны жіппен бүлдіре алмайсыз: I бөлім - жіптер » біз ағынның жіп екенін білеміз. Біз ағынның қандай да бір тапсырманы орындайтынын білеміз. Тапсырмамыздың орындалу мүмкіндігін қаласақ ( run), онда ағынды белгілі болуы үшін көрсетуіміз керек Runnable. Есте сақтау үшін Tutorialspoint Java Online CompilerСіз Java тілін жіппен бүлдіре алмайсыз: VI бөлім - Кедергіге!  - 1 пайдалана аламыз :
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();
}
Бізде құлып деген ұғым бар екенін де білеміз. Біз бұл туралы « Сіз Java-ны жіппен бүлдіре алмайсыз: II бөлім - Синхрондау » бөлімінен оқыдық . Жіп құлыпты алуы мүмкін, содан кейін құлыпты алуға тырысатын басқа ағын құлыпты босатуды күтуге мәжбүр болады:
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();
	}
}
Менің ойымша, біз қызықты тағы не істей алатынымыз туралы сөйлесетін уақыт келді.

Семафорлар

Қанша ағынның бір уақытта жұмыс істей алатынын басқарудың ең қарапайым құралы - семафор. Теміржолдағы сияқты. Жасыл шам жанып тұр - сіз аласыз. Қызыл шам жанды - біз күтеміз. Семафордан не күтеміз? Рұқсаттар. Ағылшын тіліндегі рұқсат – рұқсат. Рұқсат алу үшін сіз оны ағылшын тілінде алуыңыз керек. Ал рұқсат қажет болмай қалғанда, біз оны беруіміз керек, яғни оны босатуымыз керек немесе одан құтылуымыз керек, бұл ағылшын тілінде шығарылады. Оның қалай жұмыс істейтінін көрейік. Бізге сыныпты импорттау керек болады java.util.concurrent.Semaphore. Мысалы:
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);
}
Көріп отырғанымыздай, ағылшын сөздерін жаттап, біз семафордың қалай жұмыс істейтінін түсінеміз. Бір қызығы, негізгі шарт - семафорлық «шотта» рұқсаттардың оң саны болуы керек. Сондықтан оны минуспен бастауға болады. Ал сіз 1-ден көп сұрауға (сатып алуға) болады.

Кері санақ ысырмасы

Келесі механизм CountDownLatch. Ағылшын тіліндегі Кері санақ кері санақ, ал Latch - болт немесе ысырма. Яғни, егер біз оны аударатын болсақ, онда бұл кері санау бар ысырма. Мұнда бізге сыныптың сәйкес импорты қажет java.util.concurrent.CountDownLatch. Бәйге немесе бәйге сияқты, бәрі старт сызығына жиналып, бәрі дайын болған кезде рұқсат беріледі және бәрі бір уақытта басталады. Мысалы:
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();
 	}
}
күту ағылшын тілінде - күту. Яғни, біз бірінші сөйлейміз countDown. Google Translator айтқандай, кері санау - бұл «сандарды нөлге кері ретпен санау әрекеті», яғни кері санақ әрекетін орындау, оның мақсаты нөлге дейін санау. Содан кейін біз айтамыз await- яғни санауыш мәні нөлге айналғанша күтіңіз. Бір қызығы, мұндай есептегіш бір реттік болып табылады. JavaDoc-та айтылғандай - «Жіптер осылайша қайта-қайта кері санау керек болғанда, оның орнына CyclicBarrier пайдаланыңыз», яғни қайта пайдалануға болатын санау қажет болса, деп аталатын басқа опцияны пайдалану керек CyclicBarrier.

Циклдық кедергі

Аты айтып тұрғандай, CyclicBarrierбұл циклдік кедергі. Бізге сыныпты импорттау керек болады java.util.concurrent.CyclicBarrier. Мысал қарастырайық:
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();
	}
}
Көріп отырғаныңыздай, ағын орындалуда await, яғни күтуде. Бұл жағдайда кедергінің мәні төмендейді. Кері berrier.isBroken()санақ нөлге жеткенде тосқауыл ( ) бұзылған болып саналады. berrier.reset()Тосқауылды қалпына келтіру үшін телефонда жоқ болатын қоңырау шалу керек CountDownLatch.

Алмастырушы

Келесі ем - бұл Exchanger. Ағылшын тілінен алмасу алмасу немесе алмасу деп аударылады. А Exchanger- алмастырғыш, яғни олар арқылы алмасатын нәрсе. Қарапайым мысалды қарастырайық:
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();
}
Мұнда біз екі ағынды іске қосамыз. Олардың әрқайсысы алмасу әдісін орындайды және алмасу әдісін де орындау үшін басқа ағынды күтеді. Осылайша, ағындар өткен аргументтерді өзара алмастырады. Қызық нәрсе. Ол саған ештеңені еске түсірмейді ме? Және ол еске салады SynchronousQueue, ол 'а жүрегінде жатыр cachedThreadPool. Түсінікті болу үшін мына мысал:
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");
}
Мысал жаңа ағынды іске қосу арқылы бұл ағын күту режиміне өтетінін көрсетеді, өйткені кезек бос болады. Содан кейін mainжіп «Хабар» мәтінін кезекке қояды. Сонымен бірге ол осы мәтін элементін кезектен алғанша қажетті уақытқа тоқтайды. Бұл тақырыпта сіз « SynchronousQueue Vs Exchanger » мақаласын оқи аласыз.

Фазатор

Ақыр соңында, ең тәтті нәрсе - Phaser. Бізге сыныпты импорттау керек болады java.util.concurrent.Phaser. Қарапайым мысалды қарастырайық:
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();
    }
Мысал 'a пайдалану кезінде тосқауылдың Phaserтіркеу саны кедергіге келу санына сәйкес келген кезде бұзылатынын көрсетеді. Қосымша ақпаратты « Жаңа фазер синхронизаторыPhaser » хабындағы мақаладан біле аласыз .

Нәтижелер

Мысалдардан көріп отырғаныңыздай, ағындарды синхрондаудың әртүрлі жолдары бар. Бұрын мен көп ағын туралы бірдеңені есте сақтауға тырыстым, алдыңғы бөліктер пайдалы болды деп үміттенемін. Олар көп ағындылыққа жол «Java Concurrency in Practice» кітабынан басталады дейді. Ол 2006 жылы шыққанына қарамастан, адамдар бұл кітап өте іргелі және әлі де маңызды екенін айтады. Мысалы, талқылауларды мына жерден оқи аласыз: " Java Concurrency In Practice әлі де жарамды ма? ". Талқылаудағы сілтемелерді оқу да пайдалы. Мысалы, « Жақсы негізделген Java әзірлеушісі » кітабына сілтеме бар , онда « 4-тарау. Қазіргі заманғы параллельдікке » назар аударған жөн . Дәл осы тақырып бойынша тағы бір толық шолу бар: « Java 8 дәуірінде Java cocurrency практикалық тұрғыдан өзекті ме ?». Сондай-ақ тақырыпты шынымен түсіну үшін тағы не оқу керектігі туралы кеңестер бар. Осыдан кейін сіз « OCA OCP JavaSE 8 Programmer Practice Tests » сияқты тамаша кітапты мұқият қарай аласыз . Бізді екінші бөлім, яғни OCP қызықтырады. Ал «∫» ішінде сынақтар бар. Бұл кітапта түсініктемелері бар сұрақтар мен жауаптар бар. Мысалы: Сіз Java тілін жіппен бүлдіре алмайсыз: VI бөлім - Кедергіге!  - 3Көбісі бұл әдістердің кезекті жаттауы деп айта бастауы мүмкін. Бір жағынан, иә. Екінші жағынан, бұл сұраққа ExecutorServiceбұл «жаңарту» түрі екенін есте сақтау арқылы жауап беруге болады Executor. Және Executorбұл жай ғана ағындарды жасау әдісін жасыруға арналған, бірақ оларды орындаудың негізгі әдісі емес, яғни жаңа ағында іске қосу Runnable. Сондықтан, execute(Callable)жоқ, өйткені олар жай ғана қайтаруға болатын ExecutorServiceәдістерді Executorқосты . Көріп отырғаныңыздай, біз әдістердің тізімін жаттай аламыз, бірақ біз сабақтардың табиғатын білсек, болжау оңайырақ. Тақырып бойынша кейбір қосымша материалдар: submitFuture #Вячеслав
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION