CodeGym /وبلاگ جاوا /Random-FA /بهتر با هم: جاوا و کلاس Thread. قسمت ششم - آتش دور شوید!
John Squirrels
مرحله
San Francisco

بهتر با هم: جاوا و کلاس Thread. قسمت ششم - آتش دور شوید!

در گروه منتشر شد

معرفی

تاپیک ها چیز جالبی هستند. در بررسی‌های گذشته، ما به برخی از ابزارهای موجود برای اجرای multithreading نگاه کردیم. بیایید ببینیم چه کارهای جالب دیگری می توانیم انجام دهیم. در این مرحله، ما چیزهای زیادی می دانیم. به عنوان مثال، از " بهتر با هم: جاوا و کلاس Thread. قسمت اول - Threads of execution "، می دانیم که کلاس Thread یک رشته اجرا را نشان می دهد. ما می دانیم که یک رشته وظایفی را انجام می دهد. اگر می‌خواهیم وظایفمان قادر به انجام آن باشند run، باید موضوع را با علامت گذاری کنیم Runnable. بهتر با هم: جاوا و کلاس Thread.  قسمت ششم - آتش دور شوید!  - 1برای یادآوری، می توانیم از کامپایلر جاوا آنلاین Tutorialspoint استفاده کنیم :

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();
}
ما همچنین می دانیم که چیزی به نام قفل داریم. ما در مورد این موضوع در " بهتر با هم: کلاس جاوا و موضوع. قسمت دوم - همگام سازی" یاد گرفتیم. اگر یک رشته یک قفل دریافت کند، رشته دیگری که تلاش می کند قفل را بدست آورد مجبور می شود منتظر آزاد شدن قفل بماند:

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 مجوز درخواست (کسب) کنیم.

CountDown Latch

مکانیسم بعدی این است CountDownLatch. جای تعجب نیست که این یک چفت با شمارش معکوس است. در اینجا به دستور import مناسب برای کلاس نیاز داریم 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(). گوگل شمارش معکوس را به عنوان "عمل شمارش اعداد به ترتیب معکوس به صفر" تعریف می کند. و سپس به لچ می گوییم await()، یعنی صبر کنید تا شمارنده صفر شود. جالب اینجاست که این یک شمارنده یکبار مصرف است. اسناد جاوا می‌گوید: «وقتی رشته‌ها باید به‌طور مکرر به این روش شمارش معکوس کنند، در عوض از CyclicBarrier استفاده کنید». به عبارت دیگر، اگر به یک شمارنده قابل استفاده مجدد نیاز دارید، به گزینه دیگری نیاز دارید: CyclicBarrier.

Cyclic Barrier

همانطور که از نام آن پیداست، CyclicBarrierیک مانع "قابل استفاده مجدد" است. ما باید java.util.concurrent.CyclicBarrierکلاس را وارد کنیم. بیایید به یک مثال نگاه کنیم:

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();
	}
}
همانطور که می بینید، thread awaitمتد را اجرا می کند، یعنی منتظر می ماند. در این حالت مقدار مانع کاهش می یابد. barrier.isBroken()وقتی شمارش معکوس به صفر برسد، مانع شکسته ( ) در نظر گرفته می شود . برای تنظیم مجدد مانع، باید reset()متدی را فراخوانی کنید که CountDownLatchندارد.

مبدل

مکانیسم بعدی Exchanger است. در این زمینه، Exchange یک نقطه همگام‌سازی است که در آن چیزها تغییر می‌کنند یا مبادله می‌شوند. همانطور که انتظار دارید، an 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() + " exchanged with " + 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");
}
مثال نشان می دهد که وقتی یک رشته جدید شروع می شود، منتظر می ماند، زیرا صف خالی خواهد بود. و سپس رشته اصلی رشته "پیام" را در صف قرار می دهد. علاوه بر این، تا زمانی که این رشته از صف دریافت نشود، متوقف خواهد شد. همچنین می‌توانید « SynchronousQueue vs Exchanger » را بخوانید تا اطلاعات بیشتری در مورد این موضوع پیدا کنید.

فازر

ما بهترین ها را برای آخرین بار ذخیره کرده ایم - Phaser. ما باید java.util.concurrent.Phaserکلاس را وارد کنیم. بیایید به یک مثال ساده نگاه کنیم:

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();
    }
این مثال نشان می دهد که هنگام استفاده از Phaser, زمانی که تعداد ثبت نام ها با تعداد ورود به مانع مطابقت داشته باشد، مانع شکسته می شود. Phaserبا مطالعه این مقاله GeeksforGeeks می توانید بیشتر با آن آشنا شوید .

خلاصه

همانطور که از این مثال ها می بینید، روش های مختلفی برای همگام سازی نخ ها وجود دارد. پیش از این، سعی کردم جنبه های چند رشته ای را به خاطر بیاورم. امیدوارم قسمت های قبلی این مجموعه مفید بوده باشند. برخی می گویند مسیر چند رشته ای با کتاب «همزمانی جاوا در عمل» آغاز می شود. اگرچه این کتاب در سال 2006 منتشر شد، اما مردم می گویند که این کتاب کاملاً اساسی است و هنوز هم امروزی مرتبط است. به عنوان مثال، می توانید بحث را در اینجا بخوانید: آیا "همگامی جاوا در عمل" هنوز معتبر است؟ . خواندن پیوندهای موجود در بحث نیز مفید است. به عنوان مثال، پیوندی به کتاب The Well-Grounded Java Developer وجود دارد ، و ما به طور خاص به فصل 4 اشاره خواهیم کرد. همزمانی مدرن . همچنین یک بررسی کامل در مورد این موضوع وجود دارد: آیا "همراهی جاوا در عمل" هنوز در عصر جاوا 8 معتبر است؟ آن مقاله همچنین پیشنهاداتی در مورد مطالب دیگری برای خواندن این موضوع ارائه می دهد. پس از آن، می توانید به یک کتاب عالی مانند OCA/OCP Java SE 8 Programmer Practice Tests نگاه کنید . ما به مخفف دوم علاقه مندیم: OCP (Oracle Certified Professional). آزمون‌ها را در «فصل 20: هم‌زمانی جاوا» خواهید یافت. این کتاب دارای پرسش و پاسخ همراه با توضیحات است. به عنوان مثال: بهتر با هم: جاوا و کلاس Thread.  قسمت ششم - آتش دور شوید!  - 3بسیاری از افراد ممکن است شروع به گفتن کنند که این سوال نمونه دیگری از حفظ روش ها است. از یک طرف بله. از سوی دیگر، می‌توانید با یادآوری اینکه ExecutorServiceنوعی «ارتقا» از Executor. و Executorقصد دارد به سادگی نحوه ایجاد رشته ها را پنهان کند، اما راه اصلی برای اجرای آنها نیست، یعنی شروع یک Runnableشی در یک رشته جدید. به همین دلیل است که وجود ندارد execute(Callable)- زیرا در ExecutorService، the Executorبه سادگی submit()متدهایی را اضافه می کند که می توانند یک شی را برگردانند Future. البته، ما می‌توانیم فهرستی از روش‌ها را به خاطر بسپاریم، اما بسیار ساده‌تر است که پاسخ خود را بر اساس دانش خود از ماهیت کلاس‌ها ارائه کنیم. و در اینجا برخی از مطالب اضافی در مورد این موضوع وجود دارد: بهتر با هم: جاوا و کلاس Thread. قسمت اول - موضوعات اجرا بهتر با هم: جاوا و کلاس Thread. بخش دوم - همگام سازی بهتر با هم: کلاس جاوا و Thread. بخش سوم - تعامل بهتر با هم: کلاس جاوا و Thread. بخش چهارم - Callable، Future، و دوستان بهتر با هم: Java and the Thread کلاس. قسمت پنجم - مجری، ThreadPool، Fork/Join
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION