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

آپ دھاگے کے ساتھ جاوا کو برباد نہیں کر سکتے: حصہ I - تھریڈز

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

تعارف

ملٹی تھریڈنگ کو جاوا میں ابتدائی دنوں سے ہی بنایا گیا ہے۔ تو آئیے ایک سرسری نظر ڈالتے ہیں کہ ملٹی تھریڈنگ کیا ہے۔ آپ دھاگے کے ساتھ جاوا کو برباد نہیں کر سکتے: حصہ اول - تھریڈز - 1آئیے اوریکل سے آفیشل سبق کو نقطہ آغاز کے طور پر لیتے ہیں: " سبق: "ہیلو ورلڈ!" ایپلی کیشن "۔ آئیے اپنی ہیلو ورلڈ ایپلی کیشن کے کوڈ کو درج ذیل میں تھوڑا سا تبدیل کریں۔
class HelloWorldApp {
    public static void main(String[] args) {
        System.out.println("Hello, " + args[0]);
    }
}
argsان پٹ پیرامیٹرز کی ایک صف ہے جب پروگرام شروع ہوتا ہے۔ آئیے اس کوڈ کو اس نام کے ساتھ فائل میں محفوظ کریں جو کلاس اور ایکسٹینشن کے نام سے مماثل ہو .java۔ آئیے javac یوٹیلیٹی کا استعمال کرتے ہوئے مرتب کرتے ہیں : javac HelloWorldApp.java اس کے بعد، ہمارے کوڈ کو کچھ پیرامیٹر کے ساتھ کال کریں، مثال کے طور پر، Roger: java HelloWorldApp Roger آپ دھاگے کے ساتھ جاوا کو برباد نہیں کر سکتے: حصہ I - تھریڈز - 2ہمارے کوڈ میں اب ایک سنگین خامی ہے۔ اگر ہم کوئی دلیل پاس نہیں کرتے ہیں (یعنی صرف java HelloWorldApp کو چلاتے ہیں)، تو ہمیں ایک خرابی ملے گی:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
        at HelloWorldApp.main(HelloWorldApp.java:3)
نام کے تھریڈ میں ایک استثناء (یعنی ایک غلطی) واقع ہوئی ہے main۔ یہ پتہ چلتا ہے کہ جاوا میں کچھ قسم کے دھاگے ہیں؟ یہیں سے ہمارا سفر شروع ہوتا ہے۔

جاوا اور تھریڈز

یہ سمجھنے کے لیے کہ تھریڈ کیا ہے، آپ کو یہ سمجھنا ہوگا کہ جاوا ایپلیکیشن کیسے لانچ کی جاتی ہے۔ آئیے اپنے کوڈ کو اس طرح تبدیل کریں:
class HelloWorldApp {
    public static void main(String[] args) {
		while (true) {
			//Do nothing
		}
	}
}
اب آئیے javac کا استعمال کرتے ہوئے اسے دوبارہ مرتب کریں۔ اگلا، سہولت کے لیے، ہم اپنا جاوا کوڈ ایک الگ ونڈو میں چلائیں گے۔ ونڈوز پر آپ یہ اس طرح کر سکتے ہیں: start java HelloWorldApp. اب، jps یوٹیلیٹی کا استعمال کرتے ہوئے ، آئیے دیکھتے ہیں کہ جاوا ہمیں کیا معلومات بتائے گا: آپ دھاگے سے جاوا کو برباد نہیں کر سکتے: حصہ اول - تھریڈز - 3پہلا نمبر PID یا Process ID ہے، عمل کی شناخت کنندہ۔ ایک عمل کیا ہے؟
Процесс — это совокупность codeа и данных, разделяющих общее виртуальное addressное пространство.
عمل کی مدد سے، مختلف پروگراموں کے عمل کو ایک دوسرے سے الگ تھلگ کیا جاتا ہے: ہر ایپلیکیشن دوسرے پروگراموں میں مداخلت کیے بغیر اپنے میموری ایریا کا استعمال کرتی ہے۔ میں آپ کو مضمون کو مزید تفصیل سے پڑھنے کا مشورہ دیتا ہوں: " https://habr.com/post/164487/ "۔ ایک عمل دھاگوں کے بغیر موجود نہیں ہوسکتا، لہذا اگر کوئی عمل موجود ہے تو اس میں کم از کم ایک دھاگہ موجود ہے۔ جاوا میں یہ کیسے ہوتا ہے؟ جب ہم جاوا پروگرام چلاتے ہیں تو اس پر عمل درآمد شروع ہوتا ہے main۔ ہم پروگرام میں داخل ہوتے ہیں، لہذا اس خاص طریقہ کو mainانٹری پوائنٹ، یا "انٹری پوائنٹ" کہا جاتا ہے۔ طریقہ mainہمیشہ ایسا ہونا چاہیے public static voidکہ جاوا ورچوئل مشین (JVM) ہمارے پروگرام پر عمل درآمد شروع کر سکے۔ مزید تفصیلات کے لیے " جاوا مین طریقہ جامد کیوں ہے؟ " دیکھیں۔ یہ پتہ چلتا ہے کہ جاوا لانچر (java.exe یا javaw.exe) ایک سادہ ایپلی کیشن (سادہ سی ایپلی کیشن): یہ مختلف DLL لوڈ کرتا ہے، جو دراصل JVM ہیں۔ جاوا لانچر Java Native Interface (JNI) کالز کا ایک مخصوص سیٹ بناتا ہے۔ JNI وہ طریقہ کار ہے جو جاوا ورچوئل مشین کی دنیا اور C++ کی دنیا کو جوڑتا ہے۔ یہ پتہ چلتا ہے کہ لانچر JVM نہیں ہے، لیکن اس کا لوڈر ہے. یہ JVM کو شروع کرنے کے لیے درست حکموں کو جانتا ہے۔ جانتا ہے کہ JNI کالز کا استعمال کرتے ہوئے تمام ضروری ماحول کو کیسے ترتیب دیا جائے۔ ماحول کی اس تنظیم میں ایک مرکزی دھاگے کی تخلیق بھی شامل ہے، جسے عام طور پر کہا جاتا ہے main۔ مزید واضح طور پر یہ دیکھنے کے لیے کہ جاوا عمل میں کون سے تھریڈز رہتے ہیں، ہم jvisualvm پروگرام استعمال کرتے ہیں ، جو JDK میں شامل ہے۔ کسی عمل کی پی آئی ڈی کو جان کر، ہم اس پر فوری طور پر ڈیٹا کھول سکتے ہیں: jvisualvm --openpid айдипроцесса آپ دھاگے کے ساتھ جاوا کو برباد نہیں کر سکتے: حصہ I - تھریڈز - 4دلچسپ بات یہ ہے کہ ہر تھریڈ کی میموری میں اس کا اپنا الگ ایریا ہوتا ہے جو اس عمل کے لیے مختص ہوتا ہے۔ اس میموری کی ساخت کو اسٹیک کہا جاتا ہے۔ ایک اسٹیک فریموں پر مشتمل ہوتا ہے۔ ایک فریم ایک طریقہ کو کال کرنے کا نقطہ ہے، عملدرآمد نقطہ. ایک فریم کو StackTraceElement کے طور پر بھی پیش کیا جا سکتا ہے ( StackTraceElement کے لیے Java API دیکھیں )۔ آپ یہاں ہر تھریڈ کے لیے مختص میموری کے بارے میں مزید پڑھ سکتے ہیں ۔ اگر ہم جاوا API کو دیکھیں اور لفظ Thread تلاش کریں تو ہم دیکھیں گے کہ ایک کلاس ہے java.lang.Thread ۔ یہ وہ طبقہ ہے جو جاوا میں ایک ندی کی نمائندگی کرتا ہے، اور اسی کے ساتھ ہمیں کام کرنا ہے۔ آپ دھاگے کے ساتھ جاوا کو برباد نہیں کر سکتے: حصہ I - تھریڈز - 5

java.lang.thread

جاوا میں ایک تھریڈ کو کلاس کی مثال کے طور پر پیش کیا جاتا ہے java.lang.Thread۔ یہ فوری طور پر سمجھنے کے قابل ہے کہ جاوا میں تھریڈ کلاس کی مثالیں خود تھریڈز نہیں ہیں۔ یہ نچلے درجے کے تھریڈز کے لیے صرف ایک قسم کا API ہے جو JVM اور آپریٹنگ سسٹم کے زیر انتظام ہے۔ جب ہم جاوا لانچر کا استعمال کرتے ہوئے JVM لانچ کرتے ہیں، تو یہ ایک نام کے ساتھ ایک مرکزی دھاگہ mainاور کئی مزید سروس تھریڈز بناتا ہے۔ جیسا کہ تھریڈ کلاس کے JavaDoc میں بتایا گیا ہے: When a Java Virtual Machine starts up, there is usually a single non-daemon thread تھریڈز کی 2 اقسام ہیں: ڈیمونز اور نان ڈیمن۔ ڈیمون تھریڈز بیک گراؤنڈ تھریڈز (سروس تھریڈز) ہیں جو پس منظر میں کچھ کام کرتے ہیں۔ یہ دلچسپ اصطلاح "Maxwell's demon" کا حوالہ ہے، جس کے بارے میں آپ " شیطانوں " کے بارے میں ویکیپیڈیا کے مضمون میں مزید پڑھ سکتے ہیں۔ جیسا کہ دستاویزات میں بیان کیا گیا ہے، JVM پروگرام (عمل) کو اس وقت تک انجام دیتا رہتا ہے جب تک:
  • Runtime.exit طریقہ کو نہیں کہا جاتا ہے۔
  • تمام نان ڈیمون تھریڈز نے اپنا کام مکمل کر لیا (دونوں غلطیوں کے بغیر اور مستثنیات پھینکے گئے)
لہذا اہم تفصیل: ڈیمون تھریڈز کو کسی بھی کمانڈ پر عمل درآمد کرنے پر ختم کیا جاسکتا ہے۔ لہذا، ان میں ڈیٹا کی سالمیت کی ضمانت نہیں ہے. لہذا، ڈیمون تھریڈز کچھ خدمت کے کاموں کے لیے موزوں ہیں۔ مثال کے طور پر، جاوا میں ایک دھاگہ ہے جو کوڑا جمع کرنے والے (GC) سے متعلق حتمی طریقوں یا دھاگوں پر کارروائی کرنے کا ذمہ دار ہے۔ ہر تھریڈ کا تعلق کسی نہ کسی گروپ ( ThreadGroup ) سے ہے۔ اور گروہ ایک دوسرے میں داخل ہو سکتے ہیں، کچھ درجہ بندی یا ڈھانچہ تشکیل دے سکتے ہیں۔
public static void main(String []args){
	Thread currentThread = Thread.currentThread();
	ThreadGroup threadGroup = currentThread.getThreadGroup();
	System.out.println("Thread: " + currentThread.getName());
	System.out.println("Thread Group: " + threadGroup.getName());
	System.out.println("Parent Group: " + threadGroup.getParent().getName());
}
گروپس آپ کو بہاؤ کے انتظام کو ہموار کرنے اور ان پر نظر رکھنے کی اجازت دیتے ہیں۔ گروپس کے علاوہ، تھریڈز کا اپنا ایک استثنائی ہینڈلر ہوتا ہے۔ آئیے ایک مثال دیکھتے ہیں:
public static void main(String []args) {
	Thread th = Thread.currentThread();
	th.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
		@Override
		public void uncaughtException(Thread t, Throwable e) {
			System.out.println("An error occurred: " + e.getMessage());
		}
	});
    System.out.println(2/0);
}
صفر سے تقسیم ایک غلطی کا سبب بنے گی جو ہینڈلر کے ذریعہ پکڑا جائے گا۔ اگر آپ خود ہینڈلر کی وضاحت نہیں کرتے ہیں، تو ڈیفالٹ ہینڈلر کا نفاذ کام کرے گا، جو StdError میں ایرر اسٹیک کو ظاہر کرے گا۔ آپ جائزہ میں مزید پڑھ سکتے ہیں http://pro-java.ru/java-dlya-opytnyx/obrabotchik-neperexvachennyx-isklyuchenij-java/ "۔ اس کے علاوہ، تھریڈ کی ترجیح ہوتی ہے۔ آپ ترجیحات کے بارے میں مزید پڑھ سکتے ہیں مضمون " ملٹی تھریڈنگ میں جاوا تھریڈ کی ترجیح

ایک دھاگہ بنانا

جیسا کہ دستاویزات میں بتایا گیا ہے، ہمارے پاس تھریڈ بنانے کے 2 طریقے ہیں۔ پہلا اپنا وارث پیدا کرنا ہے۔ مثال کے طور پر:
public class HelloWorld{
    public static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("Hello, World!");
        }
    }

    public static void main(String []args){
        Thread thread = new MyThread();
        thread.start();
    }
}
جیسا کہ آپ دیکھ سکتے ہیں، کام کو طریقہ میں شروع کیا گیا ہے run، اور تھریڈ کو طریقہ میں شروع کیا گیا ہے start۔ انہیں الجھنا نہیں چاہیے، کیونکہ... اگر ہم طریقہ کو runبراہ راست چلاتے ہیں تو کوئی نیا تھریڈ شروع نہیں ہوگا۔ یہ وہ طریقہ ہے startجو JVM سے ایک نیا تھریڈ بنانے کو کہتا ہے۔ تھریڈ سے اولاد والا آپشن خراب ہے کیونکہ ہم تھریڈ کو کلاس کے درجہ بندی میں شامل کرتے ہیں۔ دوسرا نقصان یہ ہے کہ ہم "واحد ذمہ داری" SOLID کے اصول کی خلاف ورزی کرنے لگے ہیں، کیونکہ ہماری کلاس بیک وقت تھریڈ کے انتظام اور کچھ کام کے لیے ذمہ دار بن جاتی ہے جو اس تھریڈ میں انجام دینا ضروری ہے۔ کونسا ٹھیک ہے؟ جواب اسی طریقے میں ہے runجسے ہم اوور رائیڈ کرتے ہیں:
public void run() {
	if (target != null) {
		target.run();
	}
}
یہاں targetکچھ ہے java.lang.Runnable، جسے ہم کلاس کی مثال بناتے وقت Thread میں بھیج سکتے ہیں۔ لہذا، ہم یہ کر سکتے ہیں:
public class HelloWorld{
    public static void main(String []args){
        Runnable task = new Runnable() {
            public void run() {
                System.out.println("Hello, World!");
            }
        };
        Thread thread = new Thread(task);
        thread.start();
    }
}
Runnableیہ جاوا 1.8 کے بعد سے ایک فعال انٹرفیس بھی ہے۔ یہ آپ کو تھریڈز کے لیے ٹاسک کوڈ اور بھی خوبصورتی سے لکھنے کی اجازت دیتا ہے:
public static void main(String []args){
	Runnable task = () -> {
		System.out.println("Hello, World!");
	};
	Thread thread = new Thread(task);
	thread.start();
}

کل

لہذا، میں امید کرتا ہوں کہ اس کہانی سے یہ واضح ہو جائے گا کہ سٹریم کیا ہے، وہ کیسے موجود ہیں اور ان کے ساتھ کون سے بنیادی آپریشن کیے جا سکتے ہیں۔ اگلے حصے میں ، یہ سمجھنے کے قابل ہے کہ دھاگے ایک دوسرے کے ساتھ کیسے تعامل کرتے ہیں اور ان کا لائف سائیکل کیا ہے۔ #ویاچسلاو
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION