تعارف
دھاگے ایک دلچسپ چیز ہیں۔ گزشتہ جائزوں میں، ہم نے ملٹی تھریڈنگ کو لاگو کرنے کے لیے کچھ دستیاب ٹولز کو دیکھا۔ آئیے دیکھتے ہیں کہ ہم کیا دوسری دلچسپ چیزیں کر سکتے ہیں۔ اس وقت، ہم بہت کچھ جانتے ہیں. مثال کے طور پر، "
بہتر ایک ساتھ: جاوا اور تھریڈ کلاس۔ حصہ اول — پھانسی کے دھاگوں
" سے، ہم جانتے ہیں کہ تھریڈ کلاس عمل درآمد کے دھاگے کی نمائندگی کرتی ہے۔ ہم جانتے ہیں کہ تھریڈ کچھ کام انجام دیتا ہے۔ اگر ہم چاہتے ہیں کہ ہمارے کام اس قابل ہوں
run
تو ہمیں دھاگے کو نشان زد کرنا چاہیے
Runnable
۔
یاد رکھنے کے لیے، ہم
Tutorialspoint Online Java 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
۔ حیرت کی بات نہیں، یہ الٹی گنتی کے ساتھ ایک لیچ ہے۔ یہاں ہمیں کلاس کے لیے مناسب درآمدی بیان کی ضرورت ہے
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
ایک "دوبارہ قابل استعمال" رکاوٹ ہے۔ ہمیں کلاس درآمد کرنے کی ضرورت ہوگی
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();
}
}
جیسا کہ آپ دیکھ سکتے ہیں، تھریڈ
await
طریقہ چلاتا ہے، یعنی انتظار کرتا ہے۔ اس صورت میں، رکاوٹ کی قیمت کم ہو جاتی ہے.
barrier.isBroken()
جب الٹی گنتی صفر تک پہنچ جاتی ہے تو رکاوٹ کو ٹوٹا ہوا سمجھا جاتا ہے ( )۔ رکاوٹ کو دوبارہ ترتیب دینے کے لیے، آپ کو
reset()
طریقہ کار کو کال کرنے کی ضرورت ہے، جس
CountDownLatch
میں نہیں ہے۔
ایکسچینجر
اگلا میکانزم ایکسچینجر ہے۔ اس تناظر میں، ایک ایکسچینج ایک مطابقت پذیری نقطہ ہے جہاں چیزوں کو تبدیل کیا جاتا ہے یا تبدیل کیا جاتا ہے. جیسا کہ آپ توقع کریں گے، ایک
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();
phaser.register();
System.out.println("Phasecount is " + phaser.getPhase());
testPhaser(phaser);
testPhaser(phaser);
testPhaser(phaser);
Thread.sleep(3000);
phaser.arriveAndDeregister();
System.out.println("Phasecount is " + phaser.getPhase());
}
private static void testPhaser(final Phaser phaser) {
phaser.register();
new Thread(() -> {
String name = Thread.currentThread().getName();
System.out.println(name + " arrived");
phaser.arriveAndAwaitAdvance();
System.out.println(name + " after passing barrier");
}).start();
}
مثال یہ بتاتی ہے کہ استعمال کرتے وقت
Phaser
، رکاوٹ ٹوٹ جاتی ہے جب رجسٹریشن کی تعداد رکاوٹ پر آنے والوں کی تعداد سے ملتی ہے۔
آپ اس GeeksforGeeks مضمون
Phaser
کو پڑھ کر مزید واقف ہو سکتے ہیں ۔
خلاصہ
جیسا کہ آپ ان مثالوں سے دیکھ سکتے ہیں، تھریڈز کو سنکرونائز کرنے کے مختلف طریقے ہیں۔ اس سے پہلے، میں نے ملٹی تھریڈنگ کے پہلوؤں کو یاد کرنے کی کوشش کی۔ مجھے امید ہے کہ اس سیریز کی پچھلی قسطیں کارآمد تھیں۔ کچھ لوگ کہتے ہیں کہ ملٹی تھریڈنگ کا راستہ کتاب "جاوا کنکرنسی ان پریکٹس" سے شروع ہوتا ہے۔ اگرچہ یہ 2006 میں ریلیز ہوئی تھی، لیکن لوگ کہتے ہیں کہ یہ کتاب کافی بنیاد پر ہے اور آج بھی متعلقہ ہے۔ مثال کے طور پر، آپ یہاں بحث پڑھ سکتے ہیں:
کیا "جاوا کنکرنسی ان پریکٹس" اب بھی درست ہے؟
. بحث میں لنکس کو پڑھنا بھی مفید ہے۔ مثال کے طور پر، کتاب
The Well-Grounded Java Developer
کا ایک لنک ہے ، اور ہم
باب 4 کا خاص طور پر ذکر کریں گے۔ جدید کنکرنسی
۔ اس موضوع کے بارے میں ایک مکمل جائزہ بھی موجود ہے:
کیا جاوا 8 کے دور میں "جاوا ہم آہنگی" اب بھی درست ہے؟
اس مضمون میں اس بارے میں تجاویز بھی دی گئی ہیں کہ اس موضوع کو صحیح معنوں میں سمجھنے کے لیے اور کیا پڑھا جائے۔
اس کے بعد، آپ OCA/OCP Java SE 8 پروگرامر پریکٹس ٹیسٹ
جیسی بہترین کتاب پر ایک نظر ڈال سکتے ہیں ۔ ہمیں دوسرے مخفف میں دلچسپی ہے: OCP (Oracle Certified Professional)۔ آپ کو "باب 20: جاوا کنکرنسی" میں ٹیسٹ ملیں گے۔ اس کتاب میں وضاحت کے ساتھ سوالات اور جوابات دونوں ہیں۔ مثال کے طور پر:
بہت سے لوگ یہ کہنا شروع کر سکتے ہیں کہ یہ سوال طریقوں کے حفظ کی ایک اور مثال ہے۔ ایک طرف، ہاں۔ دوسری طرف، آپ اس سوال کا جواب یاد کر کے دے سکتے ہیں کہ یہ
ExecutorService
ایک قسم کا "اپ گریڈ" ہے
Executor
۔ اور
Executor
اس کا مقصد صرف دھاگوں کی تخلیق کے طریقے کو چھپانا ہے، لیکن یہ ان پر عمل کرنے کا بنیادی طریقہ نہیں ہے، یعنی
Runnable
کسی نئے دھاگے پر کسی چیز کو شروع کرنا۔ اس لیے وہاں نہیں ہے
execute(Callable)
— کیونکہ میں
ExecutorService
،
Executor
صرف
submit()
ایسے طریقے شامل کرتا ہے جو کسی
Future
چیز کو واپس کر سکتے ہیں۔ بلاشبہ، ہم طریقوں کی فہرست کو حفظ کر سکتے ہیں، لیکن کلاسوں کی نوعیت کے بارے میں ہمارے علم کی بنیاد پر اپنا جواب بنانا بہت آسان ہے۔ اور یہاں اس موضوع پر کچھ اضافی مواد ہیں:
ایک ساتھ بہتر: جاوا اور تھریڈ کلاس۔ حصہ اول — عمل درآمد کے دھاگے
ایک ساتھ بہتر: جاوا اور تھریڈ کلاس۔ حصہ دوم — ہم آہنگی
ایک ساتھ بہتر: جاوا اور تھریڈ کلاس۔ حصہ III -
ایک دوسرے کے ساتھ بہتر تعامل: جاوا اور تھریڈ کلاس۔ حصہ چہارم — کال کے قابل، مستقبل، اور دوست
ایک ساتھ بہتر: جاوا اور تھریڈ کلاس۔ حصہ V — ایگزیکیوٹر، تھریڈ پول، فورک/جوائن
GO TO FULL VERSION