JavaRush /جاوا بلاگ /Random-UR /آپ جاوا کو تھریڈ سے خراب نہیں کر سکتے: حصہ VI - رکاوٹ کی ...
Viacheslav
سطح

آپ جاوا کو تھریڈ سے خراب نہیں کر سکتے: حصہ VI - رکاوٹ کی طرف!

گروپ میں شائع ہوا۔

تعارف

اسٹریمز ایک دلچسپ چیز ہے۔ پچھلے جائزوں میں، ہم نے ملٹی تھریڈنگ کو لاگو کرنے کے لیے کچھ دستیاب ٹولز کو دیکھا۔ آئیے دیکھتے ہیں کہ ہم اور کیا دلچسپ چیزیں کر سکتے ہیں۔ اس وقت ہم بہت کچھ جانتے ہیں۔ مثال کے طور پر، " آپ جاوا کو تھریڈ سے خراب نہیں کر سکتے: حصہ I - تھریڈز، " سے ہم جانتے ہیں کہ تھریڈ ایک تھریڈ ہے۔ ہم جانتے ہیں کہ ایک تھریڈ کچھ کام کر رہا ہے۔ اگر ہم چاہتے ہیں کہ ہمارا کام چلنے کے قابل ہو ( run) تو ہمیں تھریڈ کو ایک مخصوص ہونے کے لیے بتانا چاہیے Runnable۔ آپ جاوا کو تھریڈ سے خراب نہیں کر سکتے: حصہ VI - رکاوٹ کی طرف!  - 1یاد رکھنے کے لیے، ہم 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();
}
ہم یہ بھی جانتے ہیں کہ ہمارے پاس تالا جیسا تصور ہے۔ ہم اس کے بارے میں " آپ جاوا کو تھریڈ کے ساتھ خراب نہیں کر سکتے: حصہ 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

اگلا میکانزم ہے CountDownLatch۔ انگریزی میں CountDown ایک الٹی گنتی ہے، اور Latch ایک بولٹ یا 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();
 	}
}
انگریزی میں await - توقع کرنا۔ یعنی ہم پہلے بولتے ہیں countDown۔ جیسا کہ گوگل ٹرانسلیٹر کہتا ہے، کاؤنٹ ڈاؤن "صفر کے الٹ ترتیب میں ہندسوں کو گننے کا ایک عمل" ہے، یعنی ایک الٹی گنتی کا عمل انجام دینا، جس کا مقصد صفر تک گننا ہے۔ اور پھر ہم کہتے ہیں 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۔ انگریزی سے تبادلے کا ترجمہ تبادلہ یا تبادلہ کے طور پر کیا جاتا ہے۔ A 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();
}
یہاں ہم دو تھریڈز شروع کرتے ہیں۔ ان میں سے ہر ایک تبادلے کے طریقہ کار کو انجام دیتا ہے اور تبادلے کے طریقہ کار کو انجام دینے کے لیے دوسرے دھاگے کا انتظار کرتا ہے۔ اس طرح، تھریڈز آپس میں منظور شدہ دلائل کا تبادلہ کریں گے۔ دلچسپ بات۔ کیا وہ آپ کو کچھ یاد نہیں دلاتی؟ اور وہ یاد دلاتا ہے ، جو 'a' 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();
    }
مثال سے پتہ چلتا ہے کہ رکاوٹ، Phaser'a' کا استعمال کرتے وقت ٹوٹ جاتی ہے جب رجسٹریشن کی تعداد رکاوٹ پر آنے والوں کی تعداد کے ساتھ ملتی ہے۔ Phaserآپ مضمون میں مرکز سے مزید معلومات حاصل کر سکتے ہیں " نیو فیزر سنکرونائزر

نتائج

جیسا کہ آپ مثالوں سے دیکھ سکتے ہیں، تھریڈز کو سنکرونائز کرنے کے مختلف طریقے ہیں۔ اس سے پہلے میں نے ملٹی تھریڈنگ کے بارے میں کچھ یاد کرنے کی کوشش کی، مجھے امید ہے کہ پچھلے حصے کارآمد تھے۔ ان کا کہنا ہے کہ ملٹی تھریڈنگ کا راستہ کتاب "جاوا کنکرنسی ان پریکٹس" سے شروع ہوتا ہے۔ اگرچہ یہ 2006 میں منظر عام پر آئی تھی، لوگوں نے جواب دیا کہ کتاب کافی بنیادی ہے اور پھر بھی اس میں ایک پنچ ہے۔ مثال کے طور پر، آپ یہاں بحثیں پڑھ سکتے ہیں: " کیا جاوا کنکرنسی عملی طور پر اب بھی درست ہے؟ "۔ بحث کے لنکس کو پڑھنا بھی مفید ہے۔ مثال کے طور پر، کتاب کا ایک لنک ہے " The Well-Grounded Java Developer "، جس میں " باب 4. جدید ہم آہنگی " پر توجہ دینے کے قابل ہے۔ اسی موضوع پر ایک اور مکمل جائزہ ہے: " کیا جاوا کوکرنسی عملی طور پر جاوا 8 کے دور میں اب بھی متعلقہ ہے "۔ اس میں اس بارے میں نکات بھی ہیں کہ واقعی موضوع کو سمجھنے کے لیے آپ کو اور کیا پڑھنا چاہیے۔ اس کے بعد، آپ " OCA OCP JavaSE 8 پروگرامر پریکٹس ٹیسٹ " جیسی شاندار کتاب کو قریب سے دیکھ سکتے ہیں ۔ ہمیں دوسرے حصے یعنی OCP میں دلچسپی ہے۔ اور "∫" میں ٹیسٹ ہیں۔ یہ کتاب وضاحت کے ساتھ سوالات اور جوابات پر مشتمل ہے۔ مثال کے طور پر: آپ جاوا کو تھریڈ سے خراب نہیں کر سکتے: حصہ VI - رکاوٹ کی طرف!  - 3بہت سے لوگ یہ کہنا شروع کر سکتے ہیں کہ یہ صرف طریقوں کا ایک اور حفظ ہے۔ ایک طرف، ہاں۔ دوسری طرف، اس سوال کا جواب یاد رکھ کر دیا جا سکتا ہے کہ ExecutorServiceیہ ایک قسم کا "اپ گریڈ" ہے Executor۔ اور Executorاس کا مقصد صرف تھریڈز بنانے کے طریقہ کار کو چھپانا ہے، لیکن ان پر عمل کرنے کا بنیادی طریقہ نہیں، یعنی نئے تھریڈ میں چلانا Runnable۔ لہذا، execute(Callable)نہیں، کیونکہ انہوں نے صرف ایسے طریقے شامل کیے ExecutorServiceجو واپس آسکتے ہیں ۔ جیسا کہ آپ دیکھ سکتے ہیں، ہم طریقوں کی فہرست کو حفظ کر سکتے ہیں، لیکن یہ اندازہ لگانا بہت آسان ہے کہ کیا ہم خود کلاسز کی نوعیت کو جانتے ہیں۔ ٹھیک ہے، موضوع پر کچھ اضافی مواد: ExecutorsubmitFuture #ویاچسلاو
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION