توفر سلاسل Java الافتراضية بديلاً خفيف الوزن لسلاسل عمليات نظام التشغيل التقليدية، مما يتيح إدارة التزامن بكفاءة. لكن فهم سلوكهم أمر بالغ الأهمية لتحقيق الأداء الأمثل. يتعمق منشور المدونة هذا في التثبيت، وهو سيناريو يمكن أن يؤثر على تنفيذ سلسلة الرسائل الافتراضية، ويستكشف تقنيات مراقبته ومعالجته.
سلاسل Java الافتراضية هي كيانات مُدارة تعمل فوق سلاسل عمليات نظام التشغيل الأساسي (سلاسل الناقل). إنها توفر طريقة أكثر فعالية للتعامل مع التزامن مقارنةً بإنشاء العديد من سلاسل عمليات نظام التشغيل، حيث إنها تتحمل حملًا أقل. يقوم JVM بتعيين الخيوط الافتراضية لخيوط الناقل بشكل ديناميكي، مما يسمح باستخدام أفضل للموارد.
تتم إدارتها بواسطة JVM: على عكس سلاسل عمليات نظام التشغيل التي تتم إدارتها مباشرة بواسطة نظام التشغيل، يتم إنشاء سلاسل العمليات الافتراضية وجدولتها بواسطة Java Virtual Machine (JVM). وهذا يسمح بالتحكم والتحسين الدقيق داخل بيئة JVM.
تقليل الحمل: يؤدي إنشاء وإدارة سلاسل المحادثات الافتراضية إلى تحمل حمل أقل بكثير مقارنة بسلاسل عمليات نظام التشغيل. وذلك لأن JVM يمكنه إدارة مجموعة أكبر من سلاسل العمليات الافتراضية بكفاءة، وذلك باستخدام عدد أقل من سلاسل عمليات نظام التشغيل الأساسية.
التوافق مع الكود الموجود: تم تصميم سلاسل الرسائل الافتراضية بحيث تتكامل بسلاسة مع كود Java الموجود. يمكن استخدامها جنبًا إلى جنب مع سلاسل عمليات نظام التشغيل التقليدية والعمل ضمن التركيبات المألوفة مثل Executor وExecutorService لإدارة المتزامنة.
الشكل أدناه يوضح العلاقة بين المواضيع الافتراضية وخيوط المنصة:
يحدث التثبيت عندما يصبح الخيط الظاهري مرتبطًا بخيط الناقل الخاص به. وهذا يعني بشكل أساسي أنه لا يمكن استباق الخيط الظاهري (التبديل إلى خيط ناقل آخر) أثناء وجوده في حالة مثبتة. فيما يلي السيناريوهات الشائعة التي تؤدي إلى التثبيت:
مثال الكود:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Main { public static void main(String[] args) throws InterruptedException { final Counter counter = new Counter(); Runnable task = () -> { for (int i = 0; iفي هذا المثال، عندما يدخل مؤشر ترابط افتراضي إلى الكتلة المتزامنة، فإنه يصبح مثبتًا على مؤشر ترابط الناقل الخاص به، ولكن هذا ليس صحيحًا دائمًا. لا تكفي الكلمة الأساسية المتزامنة في Java وحدها للتسبب في تثبيت سلاسل الرسائل في سلاسل الرسائل الافتراضية. لكي يحدث تثبيت الخيط، يجب أن تكون هناك نقطة حظر داخل كتلة متزامنة تتسبب في قيام الخيط الظاهري بتشغيل الإيقاف، وفي النهاية لا يسمح بإلغاء التثبيت من خيط الناقل الخاص به. قد يؤدي تثبيت الخيط إلى انخفاض في الأداء لأنه قد يلغي فوائد استخدام سلاسل الرسائل خفيفة الوزن/الافتراضية.
عندما يواجه مؤشر ترابط افتراضي نقطة حظر، يتم نقل حالته إلى PARKING. تتم الإشارة إلى انتقال الحالة هذا عن طريق استدعاء طريقة VirtualThread.park():
// JDK core code void park() { assert Thread.currentThread() == this; // complete immediately if parking permit available or interrupted if (getAndSetParkPermit(false) || interrupted) return; // park the thread setState(PARKING); try { if (!yieldContinuation()) { // park on the carrier thread when pinned parkOnCarrierThread(false, 0); } } finally { assert (Thread.currentThread() == this) && (state() == RUNNING); } }دعونا نلقي نظرة على نموذج التعليمات البرمجية لتوضيح هذا المفهوم:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Main { public static void main(String[] args) { Counter counter = new Counter(); Runnable task = () -> { for (int i = 0; i
العلامة -Djdk.tracePinnedThreads=full هي وسيطة بدء تشغيل JVM التي توفر معلومات تتبع مفصلة حول تثبيت مؤشر الترابط الظاهري. عند تمكينه، فإنه يسجل أحداثًا مثل:
استخدم هذه العلامة بحكمة أثناء جلسات تصحيح الأخطاء فقط، لأنها تؤدي إلى زيادة عبء الأداء.
قم بتجميع الكود التجريبي الخاص بنا:
javac Main.java
ابدأ الكود المترجم باستخدام العلامة -Djdk.tracePinnedThreads=full:
java -Djdk.tracePinnedThreads=full Main
لاحظ الإخراج في وحدة التحكم، والذي يعرض معلومات مفصلة حول تثبيت الخيط الافتراضي:
Thread[#29,ForkJoinPool-1-worker-1,5,CarrierThreads] java.base/java.lang.VirtualThread$VThreadContinuation.onPinned(VirtualThread.java:183) java.base/jdk.internal.vm.Continuation.onPinned0(Continuation.java:393) java.base/java.lang.VirtualThread.parkNanos(VirtualThread.java:621) java.base/java.lang.VirtualThread.sleepNanos(VirtualThread.java:791) java.base/java.lang.Thread.sleep(Thread.java:507) Counter.increment(Main.java:38)
التثبيت هو سيناريو غير مرغوب فيه والذي يعيق أداء مؤشرات الترابط الافتراضية. تعمل أقفال إعادة الدخول كأداة فعالة لمواجهة التثبيت. إليك كيفية استخدام أقفال Reentrant للتخفيف من حالات التثبيت:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.ReentrantLock; public class Main { public static void main(String[] args) { Counter counter = new Counter(); Runnable task = () -> { for (int i = 0; iفي المثال المحدث، نستخدم ReentrantLock بدلاً من الكتلة المتزامنة. يمكن للخيط الحصول على القفل وتحريره فورًا بعد اكتمال تشغيله، مما قد يقلل من مدة التثبيت مقارنة بالكتل المتزامنة التي قد تحمل القفل لفترة أطول.
ختاماً
تقف خيوط Java الافتراضية بمثابة شهادة على تطور اللغة وإمكانياتها. إنها توفر بديلاً جديدًا وخفيف الوزن لسلاسل عمليات نظام التشغيل التقليدية، مما يوفر جسرًا لإدارة التزامن بكفاءة. إن أخذ الوقت الكافي للتعمق وفهم المفاهيم الأساسية مثل تثبيت الخيوط يمكن أن يزود المطورين بالمعرفة اللازمة للاستفادة من الإمكانات الكاملة لهذه الخيوط خفيفة الوزن. لا تعمل هذه المعرفة على إعداد المطورين للاستفادة من الميزات القادمة فحسب، بل تمكّنهم أيضًا من حل مشكلات التحكم في التزامن المعقدة بشكل أكثر فعالية في مشاريعهم الحالية.
تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.
Copyright© 2022 湘ICP备2022001581号-3