Multithreading هي نقطة معرفة مهمة للغاية في Java. هنا ، يلخص المحرر لخيط Java Multithreading لك ، وهو أمر مفيد للغاية. أتمنى أن تتمكن من إتقانه.
1. دورة حياة الخيط والحالات الأساسية الخمس
فيما يتعلق بدورة حياة الخيوط في جافا ، دعونا نلقي نظرة أولاً على الصورة الكلاسيكية التالية:
يغطي الرقم أعلاه بشكل أساسي نقاط المعرفة المهمة للرواية المتعددة في Java. بمجرد إتقان نقاط المعرفة في الرقم أعلاه ، ستقوم بشكل أساسي بإتقان الروابط المتعددة في Java. بما في ذلك:
خيوط Java لها خمس حالات أساسية
حالة جديدة (جديدة): عند إنشاء زوج كائن مؤشر ترابط ، فإنه يدخل حالة جديدة ، مثل: thread t = new MyThread () ؛
حالة جاهزة (RunNable): عندما تكون طريقة Start () لكائن مؤشر الترابط (T.Start () ؛) ، يدخل مؤشر الترابط إلى الحالة الجاهزة. مؤشر ترابط في الحالة الجاهزة يعني فقط أن الخيط جاهز وينتظر وحدة المعالجة المركزية لجدولة التنفيذ في أي وقت ، وليس أن مؤشر الترابط سيتم تنفيذه مباشرة بعد تنفيذ T.Start () ؛
حالة التشغيل: عندما تبدأ وحدة المعالجة المركزية في جدولة مؤشرات الترابط في الحالة الجاهزة ، يمكن تنفيذ مؤشر الترابط حقًا ، أي أنه يدخل الحالة الجارية. ملاحظة: الحالة الجاهزة هي الإدخال الوحيد لحالة الجري ، أي إذا أراد مؤشر ترابط الدخول إلى حالة التشغيل للتنفيذ ، فيجب أن يكون أولاً في الحالة الجاهزة ؛
الحالة المحظورة: لسبب ما ، يتخلى مؤشر ترابط في حالة الجري مؤقتًا عن استخدامه لوحدة المعالجة المركزية ويوقف التنفيذ. في هذا الوقت ، يدخل حالة الحجب. لن تتاح لها الفرصة لاستدعاء وحدة المعالجة المركزية مرة أخرى لدخول حالة الجري.
وفقًا لأسباب الحجب ، يمكن تقسيم حالات الحظر إلى ثلاثة أنواع:
1. في انتظار الحظر: يقوم مؤشر الترابط في حالة التشغيل بتنفيذ طريقة WAIT () لجعل مؤشر الترابط يدخل في انتظار حالة الحظر ؛
2. الحظر المتزامن- فشل مؤشر الترابط في الحصول على قفل المزامنة المتزامن (لأن القفل يشغله مؤشرات ترابط أخرى) ، وسيدخل حالة الحجب المتزامنة ؛
3. الحظر الآخر-سيدخل الخيط حالة حظر عن طريق الاتصال بـ Sleep () أو الانضمام () من الموضوع أو إصدار طلب I/O. عندما تم توقيت Sleep () ، انتظرت الانضمام () لإنهاء الخيط أو توقيته ، أو تم الانتهاء من معالجة الإدخال/الإخراج ، حيث تم إعادة إدخال الخيط إلى الحالة الجاهزة.
Dead: انتهى الخيط من تنفيذ أو خروج طريقة Run () بسبب استثناء ، وينهي الخيط دورة حياته.
2. خلق وبدء تشغيل Java Multithreads
هناك ثلاثة أشكال أساسية لإنشاء الخيط في جافا
1. ورث فئة الخيط وتجاوز طريقة Run () للفئة.
class myThread يمتد thread {private int i = ؛ ouverridepublic void run () {for (i = ؛ i <؛ i ++) {system.out.println (thread.currentthread (). getName ()+""+i) ؛}}} threadtest {public static void (string) {system.out.println (thread.currentThRead (). getName () + "" + i) ؛ if (i ==) {thread myThRead = new MyThread () ؛ . // إنشاء موضوع جديد myThread يدخل هذا الموضوع إلى الحالة الجديدة mythread.start () ؛ // استدعاء طريقة START () لجعل مؤشر الترابط أدخل الحالة الجاهزة myThRead.start () ؛ // استدعاء طريقة START () لجعل مؤشر الترابط أدخل الحالة الجاهزة}}}}} كما هو موضح أعلاه ، ورث فئة مؤشر الترابط وتجاوز طريقة Run () ، يتم تعريف MyThread فئة مؤشرات الترابط ، حيث يمثل هيئة طريقة Run () المهمة التي يحتاجها مؤشر الترابط إلى إكمالها ، ويسمى هيئة تنفيذ مؤشر الترابط. عند إنشاء كائن فئة مؤشرات الترابط هذا ، يتم إنشاء مؤشر ترابط جديد وإدخال حالة مؤشر الترابط الجديدة. من خلال استدعاء طريقة START () المشار إليها بواسطة كائن مؤشر الترابط ، يدخل مؤشر الترابط إلى الحالة الجاهزة. في هذا الوقت ، لا يجوز تنفيذ الخيط على الفور ، اعتمادًا على توقيت جدولة وحدة المعالجة المركزية.
2. قم بتنفيذ الواجهة القابلة للتشغيل وتجاوز طريقة التشغيل () للواجهة. طريقة Run () هي أيضًا هيئة تنفيذ مؤشرات الترابط ، وإنشاء مثيل لفئة التنفيذ القابلة للتشغيل ، واستخدم هذا المثيل كهدف لفئة مؤشرات الترابط لإنشاء كائن مؤشر ترابط. كائن الخيط هو كائن مؤشر الترابط الحقيقي.
class myrunnable الأدوات runnable {private int i = ؛ verridepublic run () {for (i = ؛ i <؛ i ++) {system.out.println (thread.currentThread (). getName ()+"+i) ؛ {system.out.println (thread.currentThRead (). getName () + "" + i) ؛ if (i ==) {runnable myrunnable = new myrunnable () ؛ // قم بإنشاء كائن من مؤشر ترابط فئة تطبيق Runnable = مؤشر ترابط جديد (MyRunnable) ؛ // استخدم myrunnable كهدف مؤشر ترابط لإنشاء مؤشر ترابط مؤشر ترابط جديد = مؤشر ترابط جديد (myRunnable) ؛ thread.start () ؛ // استدعاء طريقة START () لجعل مؤشر الترابط أدخل مؤشر ترابط الحالة جاهزة () ؛}}}}} أعتقد أن الجميع على دراية بالطريقتين أعلاه لإنشاء مؤشرات ترابط جديدة. إذن ما هي العلاقة بين الخيط والركض؟ دعونا نلقي نظرة أولاً على المثال التالي.
ThreadTest stillest {public static void main (string [] args) {for (int i = ؛ i <؛ i ++) {system.out.println (thread.currentThRead (). getName () + " + i) ؛ if (i ==) myThread (myrunnable) ؛ thread.start () ؛}}}} class myrunnable تنفس Runnable {private int i = ؛ overridepublic run () {system.out.println ("in myrunnable") ؛ for (i = ؛ i ++) {system.out.println () + i) ؛}}} class myThread يمتد موضوع {private int i = ؛ public myThread (runnable runnable) {super (runnable) ؛}@overridepublic void run () {system.out.println ("in myThread Run") ؛ for (i = ؛ i ++) {system.out.println () + i) ؛}}} وبالمثل ، ينطبق الشيء نفسه على إنشاء مؤشرات ترابط تنفذ الواجهة القابلة للتشغيل ، والفرق هو ذلك
موضوع الموضوع = جديد myThread (myrunnable) ؛
فهل يمكن لهذه الطريقة إنشاء موضوع جديد بنجاح؟ الجواب نعم. أما بالنسبة لجسم تنفيذ مؤشرات الترابط في هذا الوقت ، فهل طريقة Run () في الواجهة المائية أو طريقة Run () في فئة MyThread؟ من خلال الإخراج ، نعلم أن هيئة تنفيذ مؤشر الترابط هي طريقة Run () في فئة MyThread. في الواقع ، يكون السبب بسيطًا للغاية ، لأن فئة مؤشر الترابط نفسها تنفذ أيضًا الواجهة القابلة للتشغيل ، ويتم تحديد طريقة Run () لأول مرة في الواجهة القابلة للتشغيل.
الواجهة العامة Runnable {public Abstract void Run () ؛} دعونا نلقي نظرة على تنفيذ طريقة Run () في الواجهة القابلة للتشغيل في فئة الخيط:
Overridepublic void Run () {if (target! = null) {target.run () ؛}} وهذا يعني ، عند تنفيذ طريقة Run () في فئة مؤشرات الترابط ، سيتم تحديد طريقة Run () في الهدف أولاً. إذا كانت موجودة ، يتم تنفيذ طريقة Run () في الهدف ، أي طريقة Run () في الفئة التي تنفذ الواجهة القابلة للتشغيل والكتابة فوق طريقة التشغيل (). ومع ذلك ، في الأعمدة الواردة أعلاه ، نظرًا لوجود تعدد الأشكال ، لا يتم تنفيذ طريقة Run () في فئة مؤشرات الترابط على الإطلاق ، ولكن نوع وقت التشغيل ، أي طريقة Run () في فئة MyThread يتم تنفيذها مباشرة.
3. إنشاء مؤشرات ترابط باستخدام واجهات قابلة للاتصال والمستقبلية. على وجه التحديد ، فإنه ينشئ فئة تنفيذ لواجهة قابلة للاتصال وينفذ طريقة CLALL (). واستخدم فئة FutureTask لالتفاف كائن فئة التنفيذ القابل للتطبيق ، واستخدم كائن مستقبلي مستقبلي كهدف لكائن مؤشر الترابط لإنشاء مؤشر ترابط.
يبدو الأمر معقدًا بعض الشيء ، لكن سيكون من الواضح إذا نظرت إلى مثال مباشرة.
threadtest الفئة العامة {public static void main (string [] args) {callable <integer> myCallable = new myCallable () ؛ // إنشاء mycallable futureTask <integer> ft = new FutureTask <integer> (myCallable) ؛ // استخدم futureTask لالتفاف كائن قابل للضرب لـ (int i = ؛ i <؛ i ++) {system.out.println (thread.currentThRead (). getName () + "" + i) ؛ if (i ==) {thread thread = new thread (ft) ؛ // كائن FutureTask ينشئ مؤشر ترابط جديد كهدف من مؤشر ترابط مؤشر الترابط. start () ؛ // مؤشر الترابط يدخل الحالة الجاهزة}} system.out.println ("مؤشر الترابط الرئيسي لتنفيذ الحلقة المكتمل ...") ؛ حاول {int sum = ft.get () ؛ // احصل على النتيجة التي يتم إرجاعها بواسطة طريقة call () في نظام مؤشر ترابط جديد تم إنشاؤه حديثًا. الطريقة ، تحتوي طريقة CALL () على قيمة الإرجاع ordridepublic integer call () {int sum = ؛ for (؛ i <؛ i ++) {system.out.println (thread.currentThRead (). getName () +"" +i) ؛ sum += i ؛}}}}}}} بادئ ذي بدء ، وجدنا أنه عند تنفيذ الواجهة القابلة للاتصال ، لم تعد طريقة Run () هي طريقة Run () ، ولكن طريقة Call (). طريقة Call () هي هيئة تنفيذ مؤشرات الترابط ولها أيضًا قيمة إرجاع! عند إنشاء مؤشر ترابط جديد ، يتم لف الكائن القابل للضرب من خلال مستقبلات FutureTash ويستخدم أيضًا كهدف لكائن مؤشر الترابط. ثم انظر إلى تعريف فئة FutureTask:
FutureTask public Class <V> تنفذ RunNableFuture <v> {// ....} الواجهة العامة RunNableFuture <v> يمتد Runnable ، المستقبل <v> {void run () ؛} لذلك ، وجدنا أن فئة FutureTask التي تنفذ فعليًا واجهات قابلة للتشغيل والمستقبلية ، مما يجعلها تتمتع بخصائص مزدوجة للمستقبل وقابل للتشغيل. من خلال الميزة القابلة للتشغيل ، يمكن استخدامها كهدف لكائن مؤشر الترابط ، وتسمح له الميزة المستقبلية بالحصول على قيمة الإرجاع لطريقة Call () في مؤشر الترابط الذي تم إنشاؤه حديثًا.
بعد تنفيذ هذا البرنامج ، نجد أن المبلغ = 4950 هو دائمًا الإخراج الأخير. "تم تنفيذ الخيط الرئيسي للحلقة ..." من المرجح أن يكون الإخراج في منتصف حلقة خيط الطفل. من آلية جدولة مؤشرات ترابط وحدة المعالجة المركزية ، نعلم أنه لا توجد مشكلة في توقيت الإخراج لـ "تم تنفيذ الخيط الرئيسي للحلقة ..." ، فلماذا سيتم إخراج SUM = 4950 إلى الأبد؟
والسبب هو أنه عند الحصول على طريقة () استدعاء مؤشر ترابط الطفل () من خلال طريقة ft.get () ، عندما لم يتم تنفيذ طريقة مؤشر ترابط الطفل بعد ، سيتم حظر طريقة ft.get () حتى يتم تنفيذ طريقة الاتصال () قبل الحصول على قيمة الإرجاع.
ما سبق يفسر بشكل رئيسي ثلاث طرق لإنشاء الخيط المشتركة. لبدء تشغيل المواضيع ، تسمى جميعها طريقة START () لكائن مؤشر الترابط. من المهم أن نلاحظ أنه لا يمكن استدعاء طريقة Start () مرتين على نفس كائن الخيط.
ثالثا. جاهز ، تشغيل وموت حالة Java Multithreading
يتم تحويل الحالة الجاهزة إلى حالة التشغيل: عندما يحصل هذا الموضوع على مورد المعالج ؛
يتم تحويل حالة التشغيل إلى الحالة الجاهزة: عندما يطلق هذا الموضوع بنشاط طريقة العائد () أو يفقد موارد المعالج أثناء التشغيل.
يتم تحويل حالة التشغيل إلى الحالة الميتة: عند اكتمال هيئة تنفيذ مؤشر الترابط أو حدوث استثناء.
تجدر الإشارة هنا إلى أنه عندما يتم استدعاء طريقة العائد () من مؤشر الترابط ، فإن انتقال مؤشر الترابط من الحالة الجارية إلى الحالة الجاهزة ، ولكن يتم تحديد خيط في الحالة الجاهزة في وحدة المعالجة المركزية العشوائية. لذلك ، قد يحدث أنه بعد استدعاء مؤشر الترابط طريقة العائد () ، لا تزال وحدة المعالجة المركزية تعمل على جدولة الخيط A.
نظرًا لاحتياجات العمل الفعلية ، غالبًا ما يتم مواجهة أن يتم إنهاء الخيط بفرصة محددة لجعله يدخل حالة ميتة. الطريقة الأكثر شيوعًا في الوقت الحالي هي تعيين متغير منطقي ، وعندما يتم استيفاء الشروط ، سيتم تنفيذ هيئة تنفيذ مؤشر الترابط بسرعة. يحب:
ThreadTest {public static void main (string [] args) {myrunnable myrunnable = new myrunnable () ؛ thread thread = new thread (myrunnable) ؛ for (int i = ؛ i <؛ i ++) {thread.start () ؛} if (i ==) {myrunnable.stopThread () ؛}}}} class myrunnable أدوات Runnable {private boolean stop ؛@@public run () + i) ؛}} public void stopthread () {this.stop = true ؛}}ما سبق هو تحليل شامل لخيط Java Multi-throwning الذي قدمه لك المحرر. آمل أن يكون ذلك مفيدًا لك. إذا كان لديك أي أسئلة ، فيرجى ترك رسالة لي وسوف يرد المحرر إليك في الوقت المناسب. شكرا جزيلا لدعمكم لموقع wulin.com!