ما هو جافا multhreadings
توفر Java آلية للتعامل مع المهام المتعددة بشكل متزامن (في وقت واحد ومستقل). تتعايش مؤشرات ترابط متعددة في نفس عملية JVM ، بحيث تشترك في نفس مساحة الذاكرة. بالمقارنة مع عمليات متعددة ، فإن التواصل بين خيوط متعددة أخف وزنا. في فهمي ، تعتبر Java Multithreading تمامًا تحسين استخدام وحدة المعالجة المركزية. خيوط Java لها 4 حالات: جديدة ، قابلة للتشغيل ، محظورة ، وموت. المفتاح هو حظر. الحجب يعني الانتظار. لا يشارك مؤشر ترابط الحظر في تخصيص شريحة الوقت لمرسل مؤشر الترابط ، لذلك من الطبيعي أنه لن يستخدم وحدة المعالجة المركزية. في بيئة متعددة مؤشرات الترابط ، تعمل هذه الخيوط غير المحفوظة وتستفيد بالكامل من وحدة المعالجة المركزية.
ملخص 40 سؤالا
1. ما هو استخدام متعدد الخيوط؟
سؤال قد يبدو هراءًا لكثير من الناس: يمكنني فقط استخدام متعدد الخيوط ، ولكن ما الفائدة؟ في رأيي ، هذه الإجابة أكثر هراء. ما يسمى "معرفة ما هو صحيح" هو "معرفة ما هو صحيح" ، "معرفة ما هو صحيح" ، "لماذا الاستخدام" هو "معرفة ما هو صحيح". فقط من خلال الوصول إلى مستوى "معرفة ما هو صحيح" يمكن القول أنه قادر على تطبيق نقطة المعرفة بحرية. حسنًا ، دعني أخبرك عن رأيي في هذه المشكلة:
(1) قم بتعطي تشغيل كامل لمزايا وحدة المعالجة المركزية متعددة النواة
مع تقدم الصناعة ، فإن أجهزة الكمبيوتر المحمولة اليوم وأجهزة الكمبيوتر المكتبية وحتى خوادم التطبيقات التجارية كلها نواة مزدوجة ، و 4 نواة أو 8 نواة أو حتى 16 نواة ليست شائعة. إذا كان برنامجًا واحدًا ، فإن 50 ٪ يضيع على وحدة المعالجة المركزية ثنائية النواة و 75 ٪ يضيع على وحدة المعالجة المركزية ذات 4 نواة. إن ما يسمى "متعدد الخيوط" على وحدة المعالجة المركزية ذات النواة الواحدة هو متعدد الخيوط وهمية. سيقوم المعالج بمعالجة قطعة من المنطق فقط في نفس الوقت ، ولكن تبديل مؤشرات الترابط بسرعة نسبية ، والذي يبدو أن سلسلة رسائل متعددة تعمل "في نفس الوقت". Multithreading على وحدات المعالجة المركزية متعددة النواة هي MultiThreading الحقيقية. يمكن أن يسمح منطقك متعدد القطاعات بالعمل في نفس الوقت ومتعدد الخيوط. يمكن أن يمنحهم حقًا مزايا وحدات المعالجة المركزية متعددة النواة لتحقيق هدف الاستفادة الكاملة من وحدة المعالجة المركزية.
(2) منع الانسداد
من منظور كفاءة تشغيل البرنامج ، لن تلعب وحدة المعالجة المركزية أحادية النواة اللعب الكامل فقط على مزايا متعدد الخيوط ، ولكن بدلاً من ذلك سوف يقلل من الكفاءة الإجمالية للبرنامج لأن تشغيل متعدد الخيوط على وحدة المعالجة المركزية ذات النواة الواحدة سيؤدي إلى تبديل مؤشر الترابط ، مما سيقلل من الكفاءة الكلية للبرنامج. ومع ذلك ، ما زلنا بحاجة إلى تطبيق MultiThreading على وحدات المعالجة المركزية أحادية النواة لمنع الانسداد. فقط تخيل ، إذا كانت وحدة المعالجة المركزية أحادية النواة تستخدم مؤشر ترابط واحد ، طالما تم حظر مؤشر الترابط ، على سبيل المثال ، قراءة بيانات معينة عن بُعد ، لم يتم إرجاع الأقران لفترة طويلة ولم يضع وقتًا لوقت مهلة ، ثم سيتوقف برنامجك بالكامل عن تشغيله قبل إرجاع البيانات. يمكن أن تمنع متعدد الخيوط هذه المشكلة. عدة مؤشرات ترابط تشغيل في نفس الوقت. حتى إذا تم حظر رمز مؤشر ترابط واحد من قراءة البيانات ، فلن يؤثر ذلك على تنفيذ المهام الأخرى.
(3) سهل النموذج
هذه ميزة أخرى ليست واضحة للغاية. لنفترض أن هناك مهمة كبيرة A ، برمجة أحادية الخيوط ، فأنت بحاجة إلى التفكير كثيرًا ، ومن المثير للقلق أن بناء نموذج البرنامج بأكمله. ومع ذلك ، إذا قمت بإنهاء هذه المهمة الكبيرة A إلى عدة مهام صغيرة ، المهمة B ، المهمة C ، والمهمة D ، قم بإنشاء نموذج للبرنامج بشكل منفصل ، وتشغيل هذه المهام بشكل منفصل من خلال سلسلة رسائل متعددة ، فسيكون ذلك أكثر بساطة.
2. كيفية إنشاء المواضيع
مشكلة أكثر شيوعا هي عموما اثنين:
(1) ورث فئة الخيط
(2) تنفيذ واجهة Runnable
أما بالنسبة للمرء ، فمن دون القول أن هذا الأخير هو بالتأكيد أفضل ، لأن طريقة تنفيذ الواجهات أكثر مرونة من طريقة فئة الميراث ، ويمكن أيضًا تقليل الاقتران بين البرامج. تعد البرمجة الموجهة نحو الواجهة أيضًا جوهر المبادئ الستة الرئيسية لأنماط التصميم.
3. الفرق بين طريقة start () وطريقة التشغيل ()
فقط عندما تسمى طريقة START () ، سيتم عرض خصائص الخيوط المتعددة ، وسيتم تنفيذ الكود في طريقة RUN () من مؤشرات الترابط المختلفة بالتناوب. إذا قمت فقط بالاتصال بالطريقة Run () ، فسيتم تنفيذ الكود بشكل متزامن. يجب أن تنتظر حتى يتم تنفيذ رمز Run () لتنفيذ مؤشر ترابط واحد قبل أن يتمكن مؤشر ترابط آخر من تنفيذ الكود في طريقة Run ().
4. الفرق بين واجهة Runnable وواجهة قابلة للاستدعاء
هناك القليل من السؤال العميق ، كما أنه يظهر اتساع المعرفة التي تعلمها مبرمج Java.
قيمة الإرجاع لطريقة Run () في الواجهة القابلة للتشغيل باطلة ، وما تفعله هو فقط تنفيذ الكود في طريقة Run () ؛ تحتوي طريقة CALL () في الواجهة القابلة للاتصال على قيمة إرجاع ، وهي عامة ، ويمكن استخدامها للحصول على نتائج التنفيذ غير المتزامن بالتزامن مع Future و FutureTask.
هذه في الواقع ميزة مفيدة للغاية ، لأن سببًا رئيسيًا لوجود Multithreading أكثر صعوبة وأكثر تعقيدًا من الخيوط الفردية هو أن MultiThreading مليء بالمجهول. هل تم تنفيذ موضوع معين؟ منذ متى تم تنفيذ الموضوع؟ هل البيانات التي نتوقعها عند تنفيذ مؤشر ترابط؟ لا يعلم أن كل ما يمكننا فعله هو انتظار تنفيذ هذه المهمة متعددة الخيوط. يمكن أن تحصل على نتائج التشغيل المستقبلية+Future/FutureTaLlet ، ويمكن أن تلغي مهمة الخيط عندما يكون وقت الانتظار طويلًا جدًا ولا يتم الحصول على البيانات المطلوبة. إنه مفيد حقًا.
5. الفرق بين Cyclicbarrier و CountDownlatch
يمكن استخدام كلا الفئتين التي تبدو متشابهة بعض الشيء للإشارة إلى أن الكود يعمل في نقطة معينة تحت java.util.concurrent. الفرق بين الاثنين هو:
(1) بعد تشغيل مؤشر ترابط من Cyclicbarrier عند نقطة معينة ، يتوقف الخيط عن تشغيله. حتى تصل جميع المواضيع إلى هذه النقطة ، لن يتم تشغيل جميع المواضيع مرة أخرى ؛ العد التنازلي ليس كذلك. بعد تشغيل مؤشر ترابط في نقطة معينة ، يعطي قيمة معينة -1 فقط ، ويستمر الموضوع في التشغيل.
(2) يمكن أن يثير Cyclicbarrier مهمة واحدة فقط ، حيث يمكن أن يثير CountDownlatch مهام متعددة
(3) يمكن إعادة استخدام Cyclicbarrier ، ولا يمكن إعادة استخدام CountDownlatch ، ولن يتم إعادة استخدام قيمة العد 0 ، ولن يتم استخدام CountDownlatch مرة أخرى
6. دور الكلمات الرئيسية المتطايرة
القضية المهمة للغاية هي أن كل مبرمج Java الذي يتعلم ويطبق متعدد الخيوط يجب أن يتقنه. الشرط المسبق لفهم دور الكلمة الرئيسية المتقلبة هو فهم نموذج ذاكرة Java. لن أتحدث عن نموذج ذاكرة جافا هنا. يمكنك الرجوع إلى النقطة 31. هناك وظيفتان رئيسيتان للكلمة الرئيسية المتطايرة:
(1) يدور Multithreading بشكل أساسي حول خصائص الرؤية والرؤية. تضمن المتغيرات التي تم تعديلها بواسطة الكلمة الرئيسية المتطايرة وضوحها بين مؤشرات الترابط المتعددة ، أي في كل مرة يتم فيها قراءة المتغير المتطاير ، يجب أن يكون أحدث البيانات.
(2) إن تنفيذ الكود الأساسي ليس بسيطًا مثل اللغة عالية المستوى التي نراها - برامج Java. تنفيذها هو رمز Java -> Bytecode -> تنفيذ رمز C/C ++ المقابل وفقًا لرمز Bytecode -> C/C ++ يتم تجميعه في لغة التجميع -> التفاعل مع دائرة الأجهزة. في الواقع ، من أجل الحصول على أداء أفضل ، قد يعيد JVM ترتيب التعليمات ، وقد تنشأ بعض المشكلات غير المتوقعة في ظل متعدد الخيوط. سيحظر استخدام المتقلبة إعادة ترتيب الدلالي ، مما يقلل بالطبع من كفاءة تنفيذ التعليمات البرمجية إلى حد ما
من وجهة نظر عملية ، فإن دورًا مهمًا للتقلب هو الاندماج مع CAS لضمان الذرة. للحصول على التفاصيل ، يمكنك الرجوع إلى الفصول تحت الحزمة java.util.concurrent.atomic ، مثل AtomicInteger.
7. ما هي سلامة الموضوع
سؤال نظري آخر ، هناك العديد من الإجابات. أود أن أعطي واحدة أعتقد أنها شخصياً هي أفضل تفسير: إذا كان الكود الخاص بك يمكن أن يحصل دائمًا على نفس النتيجة عند تنفيذها بموجب الرئاسة المتعددة والرواية الفردية ، فإن الكود الخاص بك آمن مؤشر ترابط.
هناك شيء جدير بالذكر حول هذه المشكلة ، أي أن هناك عدة مستويات من سلامة الخيط:
(1) ثابت
مثل السلسلة ، عدد صحيح ، طويل ، وما إلى ذلك ، كلها أنواع نهائية. لا يوجد موضوع يمكن أن يغير قيمهم. إذا كنت تريد تغييرها ، فلن تنشئ واحدة جديدة. لذلك ، يمكن استخدام هذه الكائنات غير القابلة للتغيير مباشرة في بيئة متعددة الخيوط دون أي وسيلة تزامن.
(2) سلامة الخيط المطلق
بغض النظر عن بيئة وقت التشغيل ، لا يحتاج المتصل إلى تدابير تزامن إضافية. للقيام بذلك ، عادة ما عليك دفع الكثير من التكاليف الإضافية. في جافا ، في الواقع ليس فئات آمنة مؤشرات الترابط. ومع ذلك ، هناك أيضًا فئات آمنة تمامًا ، مثل CopyOnWriteArrayList و CopyOnWriteArrayset
(3) سلامة الخيط النسبي
سلامة الخيط النسبي هي ما نسميه عادة سلامة الموضوع. على سبيل المثال ، تكون المناقصة وإضافة وإزالة الطرق هي عمليات ذرية ولن تتم مقاطعة ، ولكنها تقتصر على ذلك. إذا كان مؤشر ترابط يجتاز متجهًا معينًا ، فسيتم إضافة مؤشر ترابط في نفس الوقت ، فسيحدث ConcurrentModificationException في 99 ٪ من الحالات ، وهي آلية فاشلة.
(4) المواضيع ليست آمنة
لا يوجد شيء ليقوله عن هذا. ArrayList ، LinkedList ، Hashmap ، وما إلى ذلك كلها فصول غير متهورة.
8. كيفية الحصول على ملف تفريغ مؤشر ترابط في جافا
بالنسبة لمشاكل مثل Dead Loop ، Deadlock ، الحظر ، فتح الصفحة البطيئة ، وما إلى ذلك ، فإن ضرب مؤشر الترابط هو أفضل طريقة لحل المشكلة. تفريغ الخيط المزعوم هو مكدس الخيط. هناك خطوتان للحصول على مكدس الخيط:
(1) احصل على PID الخاص بالخيط ، يمكنك استخدام أمر JPS ، ويمكنك أيضًا استخدام PS -EF | جريب جافا في بيئة Linux
(2) طباعة مكدس مؤشر الترابط ، يمكنك استخدام أمر JSTACK PID ، ويمكنك أيضًا استخدام Kill -3 PID في بيئة Linux
أيضًا ، توفر فئة مؤشرات الترابط طريقة getStackTrace () يمكن استخدامها أيضًا للحصول على مكدس مؤشر الترابط. هذه طريقة مثيل ، لذلك ترتبط هذه الطريقة بمثيل مؤشر ترابط معين. في كل مرة تحصل فيها على المكدس الذي يعمل حاليًا على موضوع معين.
9. ماذا يحدث إذا كان للموضوع استثناء وقت التشغيل؟
إذا لم يتم القبض على هذا الاستثناء ، فسيتوقف الخيط عن التنفيذ. نقطة مهمة أخرى هي: إذا كان هذا الموضوع يحتفظ بشاشة لكائن معين ، فسيتم إصدار شاشة الكائن على الفور
10. كيفية مشاركة البيانات بين موضوعين
ما عليك سوى مشاركة الكائنات بين مؤشرات الترابط ، ثم استحوذت وانتظر من خلال الانتظار/الإخطار/الإخطار ، في انتظار/إشارة/إشارة. على سبيل المثال ، تم تصميم حظر قائمة انتظار قائمة الانتظار لمشاركة البيانات بين المواضيع.
11. ما هو الفرق بين طريقة النوم وطريقة الانتظار
يتم طرح هذا السؤال بشكل متكرر ، يمكن استخدام كل من طريقة النوم وطريقة الانتظار للتخلي عن وحدة المعالجة المركزية لفترة معينة من الزمن. الفرق هو أنه إذا كان الخيط يحتفظ بمراقبة كائن ما ، فلن تتخلى طريقة النوم عن مراقبة هذا الكائن ، وستتخلى عن طريقة الانتظار عن مراقبة هذا الكائن.
12. ما هو دور نموذج المستهلك المنتج؟
هذا السؤال نظري ، لكنه مهم:
(1) تحسين كفاءة التشغيل للنظام بأكمله من خلال موازنة القدرة الإنتاجية للمنتجين والمستهلكين ، وهو الدور الأكثر أهمية لنموذج المستهلك المنتج.
(2) فك الارتباط ، هذه هي الوظيفة التي يرافقها المنتج ونموذج المستهلك. الفصل يعني أن هناك اتصالات أقل بين المنتجين والمستهلكين. كلما زاد عدد الاتصالات ، كلما زادت تطويرها بمفردها دون تلقي قيود متبادلة.
13. ما هو استخدام threadlocal
ببساطة ، threadlocal هي ممارسة لتبادل المساحة للوقت. يحافظ كل مؤشر ترابط على threadlocal.ThreadLocalmap التي تم تنفيذها بواسطة طريقة العنوان المفتوح لعزل البيانات وعدم مشاركة البيانات ، لذلك لن تكون هناك مشكلات سلامة مؤشر ترابط.
14. لماذا يتم استدعاء أساليب الانتظار () وإخطار ()/إخطار () في كتلة التزامن
هذا يجبر من قبل JDK. يجب أولاً الحصول أولاً على طريقة Wait () و Amply ()/elefyall ()
15. ما هو الفرق بين طريقة الانتظار () وطريقة إخطار ()/إخطار () عند التخلي عن شاشة الكائن
الفرق بين طريقة WAIT () وطريقة إخطار ()/notifyall () عند التخلي عن مراقبة الكائن هي أن طريقة WAID () تطلق فورًا مراقبة الكائن ، بينما ستنتظر طريقة الإخطار ()/motifyall () حتى يتم تنفيذ الكود المتبقي للمعلومات قبل التخلي عن مراقبة الكائن.
16. لماذا تستخدم تجمع الخيوط
تجنب الخلق المتكرر وتدمير الخيوط لتحقيق إعادة استخدام كائنات الخيط. بالإضافة إلى ذلك ، يمكن استخدام تجمعات مؤشرات الترابط أيضًا التحكم في عدد التزامن وفقًا للمشروع.
17. كيفية اكتشاف ما إذا كان مؤشر ترابط يحمل شاشة كائن
لقد رأيت أيضًا سؤالًا مقابلة متعدد التشبسيات على الإنترنت لأعلم أن هناك طريقة لتحديد ما إذا كان مؤشر ترابط يحتفظ بشاشة كائن: توفر فئة مؤشرات الترابط طريقة HoldSlock (Object OBJ) ، والتي ستعود بشكل صحيح إذا وفقط إذا تم الاحتفاظ بمراقبة الكائن OBJ بواسطة مؤشر ترابط. لاحظ أن هذه طريقة ثابتة ، مما يعني أن "مؤشر ترابط معين" يشير إلى مؤشر الترابط الحالي.
18. الفرق بين متزامن و reenrantlock
المزامنة هي نفس الكلمة الرئيسية كما لو كان ، وإلا ، وبينما ، و reentrantlock هو فئة ، وهو الفرق الأساسي بين الاثنين. نظرًا لأن Reentrantlock عبارة عن فئة ، فإنه يوفر ميزات أكثر وأكثر مرونة أكثر من متزامن ، والتي يمكن أن تكون موروثة ، ولديها طرق ، ولها متغيرات فئة مختلفة. تنعكس قابلية إعادة توسيع نطاق إعادة توسيعها من المزامنة في عدة نقاط:
(1) يمكن لإعادة إيندرانتوك تعيين وقت الانتظار لاكتساب القفل ، وبالتالي تجنب readlock
(2) يمكن لـ reentrantlock الحصول على معلومات قفل مختلفة
(3) يمكن أن تنفذ REENCENTRANTLOCK إشعارًا متعدد القنوات بمرونة
بالإضافة إلى ذلك ، فإن آليات القفل للاثنين مختلفة في الواقع. يستدعي REENTRANTLOCK الأساسي طريقة حديقة UNSAFE إلى قفل ، ويجب أن تكون العملية المتزامنة هي كلمة العلامة في رأس الكائن ، ولا يمكنني التأكد من ذلك.
19. ما هو تزامن concurrenthashmap
إن توافق ConcurrentHashMap هو حجم القطاع ، وهو 16 بشكل افتراضي ، مما يعني أنه في أكثر من 16 خيوط يمكن أن تعمل concurrenthashmap في نفس الوقت. هذه هي أيضًا أكبر ميزة لـ ConcurrenthashMap على علامة التجزئة. في أي حال ، هل يمكن أن يكون للهاش في نفس الوقت الحصول على البيانات في علامة التصنيف؟
20. ما هو readwritelock
بادئ ذي بدء ، دعونا نوضح أنه ليس من أن reentrantlock ليس جيدًا ، بل هو مجرد إعادة إينترانتلوك في بعض الأحيان. إذا تم استخدام reentrantlock ، فقد يكون ذلك هو منع تناقضات البيانات الناتجة عن بيانات الخيط A بيانات الكتابة وبيانات قراءة الخيط B. ومع ذلك ، وبهذه الطريقة ، إذا كان مؤشر ترابط القراءة C وقراءة مؤشر الترابط D يقرأ أيضًا البيانات ، فلن تقوم قراءة البيانات بتغيير البيانات. ليست هناك حاجة إلى قفلها ، لكنها لا تزال تغلقها ، مما يقلل من أداء البرنامج.
ولهذا السبب ، ولدت قفل القراءة القراءة. ReadWritelock هي واجهة قفل القراءة. REENTRANTREADWRITELOCK هو تطبيق ملموس لواجهة ReadWritelock ، والتي تدرك فصل القراءة والكتابة. يتم مشاركة أقفال القراءة وكتابة الأقفال حصرية. القراءة والقراءة والقراءة لن تكون حصرية بشكل متبادل. فقط القراءة والكتابة والكتابة والكتابة والكتابة ستكون حصرية بشكل متبادل ، وتحسين أداء القراءة والكتابة.
21. ما هو مستقبلات مستقبلية
هذا بالفعل مذكور سابقا. يمثل FutureTask مهمة تشغيل غير متزامنة. يمكن نقل فئة تنفيذ محددة من قابلية الاتصال إلى مستقبلات ، والتي يمكن أن تنتظر نتيجة هذه العملية غير المتزامنة ، وتحديد ما إذا كانت قد اكتملت ، وإلغاء المهمة. بالطبع ، نظرًا لأن FutureTask هي أيضًا فئة تنفيذ لواجهة Runnable ، يمكن أيضًا وضع FutureTask في تجمع الخيوط.
22. كيفية العثور على خيط يستخدم أطول وحدة المعالجة المركزية في بيئة Linux
هذه مشكلة أكثر عملية ، وأعتقد أن هذه المشكلة ذات مغزى للغاية. يمكنك القيام بذلك:
(1) الحصول على PID للمشروع ، JPS أو PS -EF | جريب جافا ، الذي تم ذكره من قبل
(2) TOP -H -P PID ، لا يمكن تغيير الترتيب
سيؤدي ذلك إلى طباعة النسبة المئوية لوقت وحدة المعالجة المركزية التي يأخذها المشروع الحالي لكل موضوع. لاحظ أن واحد هنا هو LWP ، وهو رقم مؤشر ترابط مؤشر الترابط الأصلي لنظام التشغيل. لا ينشر My Book Mountain مشاريع Java في بيئة Linux ، لذلك لا توجد طريقة لالتقاط لقطات الشاشة والمظاهرات. إذا كانت الشركة تنشر مشروعًا باستخدام بيئة Linux ، فيمكنك تجربته.
يمكن أن يجد "Top -H -P Pid" + "JPS PID" بسهولة مكدس مؤشر ترابط يحتل وحدة المعالجة المركزية العالية ، وبالتالي وضع سبب شغل وحدة المعالجة المركزية العالية ، والذي يرجع عمومًا إلى عمليات الكود غير الصحيحة التي تؤدي إلى حلقة ميتة.
أخيرًا ، اسمحوا لي أن أذكر أن LWP لعبت مع "Top -H -P Pid" هو عشري ، وأن رقم الخيط المحلي لعب مع "JPS PID" هو سداسي عشري. بعد التحويل ، يمكنك تحديد موقع مكدس الخيط الحالي الذي يحتل وحدة المعالجة المركزية العالية.
23. برمجة Java اكتب برنامجًا سيؤدي إلى طريق مسدود
رأيت هذا السؤال لأول مرة واعتقدت أنه كان سؤالًا جيدًا للغاية. يعرف الكثير من الناس كيف يشبه Deadlock: الخيط A و Thread B ينتظران أقفال بعضهما البعض للتسبب في حلقة Dead Infinite لمواصلة البرنامج. بالطبع ، يقتصر فقط على هذا. إذا سألت عن كيفية كتابة برنامج Deadlock ، فلن تعرف ذلك. بعبارة صريحة ، أنت لا تفهم ماهية المسدود. إذا فهمت نظرية ، فسوف تنتهي. لا يمكنك رؤية مشكلة adadlock في الممارسة.
لفهم حقًا ماهية المسدود ، هذا السؤال ليس صعبًا ، فهناك بضع خطوات:
(1) يحمل مؤشر ترابط كائنين كائنين: lock1 و lock2 على التوالي. هذان الأقفان يعملان كأقفال لكتل التعليمات البرمجية المتزامنة ؛
(2) في طريقة Run () من مؤشر الترابط 1 ، تحصل كتلة رمز التزامن أولاً على قفل كائن Lock1 ، thread.sleep (xxx) ، لا يستغرق الوقت أكثر من اللازم ، 50 ميلي ثانية تقريبًا ، ثم يحصل على قفل كائن Lock2. يتم ذلك بشكل رئيسي لمنع الموضوع 1 من الحصول على أقفال كائن مستمر لكائنين: Lock1 و Lock2.
(3) تشغيل مؤشر الترابط 2) (في الطريقة ، تحصل كتلة رمز التزامن أولاً على قفل الكائن 2 ، ثم يحصل على قفل الكائن.
وبهذه الطريقة ، بعد أن اكتسبت الموضوع 1 "النوم" والخيط 2 قد اكتسب كائن Lock2. يحاول الموضوع 1 الحصول على كائن Lock2 في هذا الوقت ، ويتم حظره. في هذا الوقت ، يتم تشكيل طريق مسدود. لن أكتب الرمز بعد الآن ، فهو يشغل مساحة كبيرة. Java Multithreading 7: Deadlock تحتوي هذه المقالة على تنفيذ الكود للخطوات المذكورة أعلاه.
24. كيف تستيقظ خيط حظر
إذا كان الخيط يحظر أساليب الاتصال (WAIT () أو Sleep () أو الانضمام إلى () ، فيمكنه مقاطعة الخيط وإيقاظه عن طريق رمي مقاطع المقاطع ؛ إذا واجه مؤشر الترابط انسداد IO ، فسيكون عاجزًا لأنه يتم تنفيذ IO بواسطة نظام التشغيل ، ولا يمكن لـ Java Code الاتصال مباشرة بنظام التشغيل.
25. ما هي المساعدة التي تساعدها الأشياء غير القابلة للتغيير في التعددية
المشكلة المذكورة أعلاه هي أن الكائنات غير القابلة للتغيير تضمن رؤية ذاكرة الكائنات ، وليس هناك حاجة لمزامنة إضافية لقراءة الكائنات الثابتة ، مما يحسن كفاءة تنفيذ الكود.
26. ما هو تبديل السياق متعدد الخيوط
يشير تبديل السياق متعدد مؤشرات الترابط إلى عملية تبديل التحكم في وحدة المعالجة المركزية من مؤشر ترابط واحد إلى مؤشر ترابط آخر جاهز وانتظار الحصول على حقوق تنفيذ وحدة المعالجة المركزية.
27. إذا كانت قائمة انتظار تجمع الخيوط ممتلئة عند إرسال مهمة ، فما الذي سيحدث في هذا الوقت
إذا كنت تستخدم LinkedBlockingQueue ، وهذا هو ، طوابير غير محدودة ، لا يهم. استمر في إضافة مهام إلى قائمة انتظار الحظر وانتظر التنفيذ ، لأن LinkedBlockingqueue يمكن اعتبارها قائمة انتظار لا حصر لها ويمكن أن تخزن المهام بلا حدود ؛ إذا كنت تستخدم قائمة انتظار محددة ، على سبيل المثال ، ArrayBlockingQueue ، فسيتم إضافة المهمة إلى ArrayBlockingQueue أولاً. إذا كانت ArrayBlockingqueue ممتلئة ، فسيستخدم DesideDexecutionHandler سياسة الرفض للتعامل مع المهام الكاملة ، ويكون الافتراضي مشحوبًا.
28. ما هي خوارزمية جدولة الخيط المستخدمة في جافا؟
أسلوب وقائي. بعد أن يستخدم مؤشر ترابط وحدة المعالجة المركزية ، سيقوم نظام التشغيل بحساب أولوية إجمالية بناءً على بيانات مثل أولوية مؤشر الترابط ، والجوع في مؤشر الترابط ، وما إلى ذلك وتخصيص شريحة في المرة التالية إلى مؤشر ترابط للتنفيذ.
29. ما هي وظيفة thread.sleep (0)
يرتبط هذا السؤال بالسؤال أعلاه ، وأنا جميعًا معًا. نظرًا لأن Java يستخدم خوارزمية جدولة الخيط الوقائي ، فقد يحدث أن يكون مؤشر ترابط في كثير من الأحيان يحصل على التحكم في وحدة المعالجة المركزية. من أجل السماح لبعض المواضيع ذات الأولوية المنخفضة نسبيًا للحصول على التحكم في وحدة المعالجة المركزية ، يمكن استخدام thread.sleep (0) لتشغيل نظام التشغيل تخصيص نظام التشغيل يدويًا ، وهو أيضًا عملية لموازنة التحكم في وحدة المعالجة المركزية.
30. ما هو الدوران
العديد من الرموز المتزامنة هي مجرد رمز بسيط للغاية ، ووقت التنفيذ سريع للغاية. قد يكون قفل المواضيع التي تنتظر في هذا الوقت عملية لا جديرة بالاهتمام ، لأن حظر مؤشرات الترابط يتضمن تبديل الحالة والدولة kernel. نظرًا لأن الكود الموجود في Synchronized ينفذ بسرعة كبيرة ، فقد تدع الخيط أيضًا في انتظار عدم حظر القفل ، ولكن بدلاً من ذلك قم بالقيام بحلقات مزدحمة على حدود المزامنة. هذا هو الدوران. إذا كنت قد قمت بعدة حلقات مشغولة ووجدت أنه لم يتم الحصول على القفل ، ثم منعه ، فقد تكون هذه استراتيجية أفضل.
31. ما هو نموذج ذاكرة جافا
يحدد نموذج ذاكرة Java مواصفات للوصول متعدد الخيوط إلى ذاكرة Java. يجب شرح نموذج ذاكرة Java بالكامل ، لكن لا يمكنني شرح ذلك بوضوح في بضع جمل هنا. اسمحوا لي أن ألخص ذلك لفترة وجيزة.
عدة أجزاء من نموذج ذاكرة جافا:
(1) يقسم نموذج ذاكرة Java الذاكرة إلى الذاكرة الرئيسية والذاكرة العاملة. يتم تخزين حالة الفصل ، أي المتغيرات المشتركة بين الفئات ، في الذاكرة الرئيسية. في كل مرة يستخدم مؤشر ترابط Java هذه المتغيرات في الذاكرة الرئيسية ، سيقرأ المتغيرات في الذاكرة الرئيسية ويسمح لها بوجودها في ذاكرتها العاملة. عند تشغيل رمز مؤشر الترابط الخاص به ، فإنه يستخدم هذه المتغيرات ويدير المتغيرات في ذاكرته العاملة. بعد تنفيذ رمز الموضوع ، سيتم تحديث أحدث قيمة إلى الذاكرة الرئيسية.
(2) يتم تعريف العديد من العمليات الذرية لتشغيل المتغيرات في الذاكرة الرئيسية وذاكرة العمل
(3) تحديد القواعد لاستخدام المتغيرات المتطايرة
(4)-قبل أن ، أي مبدأ الحدوث الأول ، يحدد بعض القواعد التي يجب أن تحدث فيها العملية A أولاً في العملية B. على سبيل المثال ، يجب أن يحدث الكود أمام تدفق التحكم في نفس الخيط أولاً في الكود وراء تدفق التحكم ، ولا يجب أن يحدث إجراء إصدار إلغاء القفل أولاً في إجراء قفل نفس القفل ، وما إلى ذلك ، حيث أن هذه القواعد تتنقل. إذا لم يتوافق جزء معين من التعليمات البرمجية مع جميع القواعد التي تحدث قبل ذلك ، فيجب أن تكون قطعة الكود هذه غير آمنة.
32. ما هو CAS
CAS ، الاسم الكامل المقارنة والتعيين ، هو المقارنة. لنفترض أن هناك ثلاثة معاملات: قيمة الذاكرة V ، القيمة القديمة المتوقعة ، القيمة B المراد تعديلها. إذا كانت القيمة المتوقعة وقيمة الذاكرة V هي نفسها فقط ، فسيتم تعديل قيمة الذاكرة إلى B وإعادتها بشكل صحيح ، وإلا فلن يتم القيام بأي شيء وسيتم إرجاع خطأ. بطبيعة الحال ، يجب أن تتعاون CAS مع المتغير المتقلبة ، وذلك لضمان أن المتغير الذي تم الحصول عليه في كل مرة هو أحدث قيمة في الذاكرة الرئيسية. خلاف ذلك ، فإن القيمة القديمة المتوقعة A ستكون دائمًا قيمة A التي لن تتغير لخيط ما. طالما فشل عملية CAS معينة ، فلن تنجح أبدًا.
33. ما هو القفل المتفائل والقفل المتشائم
(1) قفل متفائل: تمامًا مثل اسمه ، إنه متفائل بشأن مشكلات سلامة مؤشرات الترابط الناتجة عن العمليات المتزامنة. يعتقد القفل المتفائل أن المنافسة لا تحدث دائمًا ، لذلك لا تحتاج إلى الاحتفاظ بالقفل ، وسوف تقارن - تعيين هذين الإجراءين كعملية ذرية لمحاولة تعديل المتغيرات في الذاكرة. إذا فشلت ، فهذا يعني حدوث تعارض ، وبعد ذلك يجب أن يكون هناك منطق إعادة المحاولة المقابل.
(2) القفل المتشائم: تمامًا مثل اسمه ، إنه متشائم حول مشكلات سلامة الخيوط الناجمة عن العمليات المتزامنة. يعتقد الأقفال المتشائمة أن المنافسة ستحدث دائمًا. لذلك ، في كل مرة يتم فيها تشغيل مورد ، سيحمل قفلًا حصريًا ، تمامًا مثل المزامنة ، بغض النظر عما إذا كان مغلقًا مباشرة ، وسيتم تشغيل المورد.
34. ما هو AQS
دعنا نتحدث بإيجاز عن AQS. الاسم الكامل لل AQS هو الملخص. يجب أن يكون مزامنة قائمة انتظار مجردة عند ترجمتها.
إذا كان أساس java.util.concurrent هو CAS ، فإن AQS هو جوهر حزمة Concurrency بأكملها ، و reentrantlock ، countdownlatch ، semaphore ، إلخ. AQS في الواقع يربط جميع الإدخال في شكل قائمة انتظار ثنائية الاتجاه. على سبيل المثال ، reentrantlock. يتم وضع جميع خيوط الانتظار في إدخال وتوصيلها في قائمة انتظار ثنائية الاتجاه. إذا كان الخيط السابق يستخدم reentrantlock ، فإن الإدخال الأول لقائمة الانتظار ثنائية الاتجاه يبدأ بالفعل في التشغيل.
تحدد AQS جميع العمليات على قوائم قوائم ثنائية الاتجاه ، ولكنها تفتح فقط طرق Trylock و TryRelease للمطورين لاستخدامها. يمكن للمطورين إعادة كتابة أساليب Trylock و TryRelease وفقًا لتنفيذهم الخاص لتنفيذ وظائف التزامن الخاصة بهم.
35. موضوع السلامة من وضع سينجلتون
قضية كليشيهات ، أول ما يمكن قوله هو أن سلامة مؤشر ترابط نمط المفرد تعني ما يلي: لن يتم إنشاء حالات فئة معينة إلا مرة واحدة في بيئة متعددة الخيوط. هناك العديد من الطرق لكتابة نمط المفرد ، اسمحوا لي أن ألخص:
(1) كتابة نمط المفرد للرجل الجائع: سلامة الموضوع
(2) كتابة النمط المفرد الكسول: غير آمن
(3) اكتب وضع Singleton من قفل التحقق المزدوج: سلامة الموضوع
36. ما هي وظيفة الإشارة
Semaphore هي إشارة ، ووظائفها هي الحد من عدد التزامن في كتلة رمز معينة. يحتوي Semaphore على مُنشئ يمكن أن يمرر INT INTEGER N ، مما يشير إلى أن مؤشرات الترابط N فقط يمكنها الوصول إلى جزء معين من التعليمات البرمجية. إذا تم تجاوز N ، يرجى الانتظار حتى يقوم مؤشر ترابط بإنجاز كتلة الكود وإدخال مؤشر الترابط التالي. من هذا ، يمكننا أن نرى أنه إذا تم تمرير عدد صحيح int n = 1 في مُنشئ الإشارة إلى أن يصبح متزامنًا.
37. لا يوجد سوى بيان واحد "عدد الإرجاع" في طريقة الحجم () من علامة التصنيف ، فلماذا لا تزال بحاجة إلى مزامنة؟
هذا ارتباك كان لدي من قبل ، وأتساءل عما إذا كنت قد فكرت في هذا السؤال. إذا كانت هناك عبارات متعددة في طريقة ما ، وكلها تعمل على نفس متغير الفئة ، فإذا لم تضيف أقفال في بيئة متعددة الخيوط ، فسيؤدي ذلك حتماً إلى مشكلات سلامة مؤشرات الترابط. من السهل فهم هذا ، ولكن من الواضح أن طريقة Size () تحتوي على بيان واحد فقط ، فلماذا لا تزال بحاجة إلى إضافة أقفال؟
فيما يتعلق بهذه المشكلة ، لقد فهمتها من خلال العمل والدراسة ببطء ، وهناك سببين رئيسيين:
(1) يمكن لخيط واحد فقط تنفيذ طريقة التزامن للفئة الثابتة في نفس الوقت ، ولكن بالنسبة للطريقة غير المتزامنة للفئة ، يمكن لخيوط متعددة الوصول إليها في نفس الوقت. لذلك ، هناك مشكلة. ربما يقوم مؤشر الترابط A بإضافة بيانات عند تنفيذ طريقة وضع علامة التجزئة ، ويمكن للمعلومات B استدعاء طريقة Size () عادة لقراءة عدد العناصر الحالية في علامة التجزئة. قد لا تكون قراءة القيمة هي الأحدث. ربما أضاف الموضوع A البيانات ، ولكن بدون Size ++ ، قرأ الموضوع B الحجم بالفعل. لذلك بالنسبة للموضوع B ، يجب أن تكون قراءة الحجم غير دقيقة. بعد إضافة التزامن إلى طريقة Size () ، فهذا يعني أن الخيط B يستدعي طريقة Size () فقط بعد ترابط A.
(2) تقوم وحدة المعالجة المركزية بتنفيذ الكود ، لكنها ليست رمز Java. هذا مهم للغاية ويجب أن تتذكره. تتم ترجمة رمز Java في النهاية إلى رمز التجميع للتنفيذ ، ورمز التجميع هو الرمز الذي يمكن أن يتفاعل حقًا مع دوائر الأجهزة. حتى لو رأيت أنه لا يوجد سوى سطر واحد من رمز Java ، وحتى إذا رأيت أنه تم تجميع رمز Java ، فهناك سطر واحد فقط من رمز البايت الذي تم إنشاؤه ، فهذا لا يعني أنه بالنسبة للطبقة الأساسية ، لا يوجد سوى عملية واحدة لهذا البيان. تفترض الجملة "عدد الإرجاع" أنه يتم ترجمته إلى ثلاثة عبارات تجميعية للتنفيذ ، ومن الممكن تمامًا أن يتحول مؤشر الترابط بعد تنفيذ الجملة الأولى.
38. أي موضوع هو مُنشئ فئة الخيط والكتلة الثابتة التي تسمى الخيط
هذا سؤال صعب للغاية ومسمم. يرجى تذكر: يتم استدعاء المُنشئ والكتلة الثابتة لفئة مؤشرات الترابط بواسطة مؤشر الترابط حيث توجد فئة مؤشرات الترابط الجديدة ، ويتم استدعاء الكود في طريقة التشغيل بواسطة مؤشر الترابط نفسه.
إذا كان البيان أعلاه يربكك ، فدعني أعطيك مثالًا ، افترض أن Thread1 الجديد موجود في Thread2 و New Thread2 في الوظيفة الرئيسية ، ثم:
(1) يتم استدعاء مُنشئ Thread2 وكتلة ثابتة بواسطة مؤشر الترابط الرئيسي ، ويسمى طريقة Run () Thread2 بواسطة Thread2 نفسه
(2) مُنشئ Thread1 وكتلة ثابتة يسمى بواسطة Thread2 ، ويسمى طريقة Run () Thread1 بواسطة Thread1 نفسه
39. ما هو الخيار الأفضل بين طريقة التزامن وكتلة التزامن؟
تزامن الكتل ، مما يعني أن الكود خارج كتلة التزامن يتم تنفيذه بشكل غير متزامن ، مما يحسن كفاءة الكود أكثر كفاءة من مزامنة الطريقة بأكملها. يرجى معرفة مبدأ واحد: نطاق التزامن الأقل
أفضل.
مع هذه المقالة ، أود أن أذكر أنه على الرغم من أصغر نطاق التزامن ، كلما كان ذلك أفضل ، لا يزال هناك طريقة تحسين تسمى القفل الخشنة في الأجهزة الافتراضية Java ، والتي تتمثل في زيادة نطاق التزامن. هذا مفيد. على سبيل المثال ، StringBuffer هو فئة آمنة مؤشرات الترابط. وبطبيعة الحال ، فإن طريقة التزامن الأكثر شيوعًا () هي طريقة التزامن. عندما نكتب رمزًا ، سنقوم بإلحاق السلسلة مرارًا وتكرارًا ، مما يعني قفل مرارًا وتكرارًا -> إلغاء القفل ، وهو أمر غير جيد للأداء ، لأنه يعني أن الجهاز الظاهري Java يجب أن يتحول بشكل متكرر بين حالة kernel وحالة المستخدم في هذا الموضوع. لذلك ، يقوم جهاز Java Virtual بإجراء عملية قفل على الرمز الذي تسمى طريقة الإلحاق المتعددة ، وتوسيع عمليات الإلحاق المتعددة إلى رأس وذيل طريقة الإلحاق ، وتحويلها إلى كتلة مزامنة كبيرة. هذا يقلل من عدد أوقات القفل-> فتح الأوقات ، مما يؤدي بشكل فعال إلى تحسين كفاءة تنفيذ التعليمات البرمجية.
40. كيفية استخدام تجمعات الخيوط للشركات ذات التزامن العالي ووقت تنفيذ المهام القصير؟ كيفية استخدام تجمعات الخيوط للشركات ذات التزامن المنخفض ووقت تنفيذ المهام الطويل؟ كيفية استخدام تجمعات الخيوط للشركات ذات التزامن العالي ووقت تنفيذ الخدمة الطويل؟
هذا سؤال رأيته على موقع البرمجة المتزامنة. أضع هذا السؤال أخيرًا وأتمنى أن يرى الجميع ويفكرون في الأمر ، لأن هذا السؤال جيد جدًا وعملي للغاية ومهني للغاية. فيما يتعلق بهذه القضية ، رأيي الشخصي هو:
(1) التزامن العالي ووقت تنفيذ المهمة القصير ، يمكن تعيين عدد مؤشرات ترابط تجمع مؤشرات الترابط على رقم CPU CORE +1 لتقليل تبديل سياق مؤشر الترابط
(2)并发不高、任务执行时间长的业务要区分开看:
a)假如是业务时间长集中在IO操作上,也就是IO密集型的任务,因为IO操作并不占用CPU,所以不要让所有的CPU闲下来,可以加大线程池中的线程数目,让CPU处理更多的业务
b)假如是业务时间长集中在计算操作上,也就是计算密集型任务,这个就没办法了,和(1)一样吧,线程池中的线程数设置得少一些,减少线程上下文的切换
(3)并发高、业务执行时间长,解决这种类型任务的关键不在于线程池而在于整体架构的设计,看看这些业务里面某些数据是否能做缓存是第一步,增加服务器是第二步,至于线程池的设置,设置参考(2)。最后,业务执行时间长的问题,也可能需要分析一下,看看能不能使用中间件对任务进行拆分和解耦。
Java线程阻塞(Blocked)的类型:
调用sleep函数进入睡眠状态,Thread.sleep(1000)或者TimeUnit.SECONDS.sleep(1),sleep不会释放锁。
等待(wait)某个事件,分为两种,(wait,notify,notifyAll),(await, signal,signalAll) ,后面会详细介绍。wait和await会释放锁,且必须在获取到锁的环境才能调用。
等待锁,synchronized和lock环境中,锁已经被别的线程拿走,等待获取锁。
IO阻塞(Blocked),比如网络等待,文件打开,控制台读取。System.in.read()。