StampedLock والقراءات المتفائلة
طبّق وضع القراءة المتفائلة في StampedLock لأحمال العمل عالية الإنتاجية التي يغلب عليها القراءة
StampedLock والقراءات المتفائلة درس مجاني في Java Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Java Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Java Academy 4 دروس في المجموع.
ما هو StampedLock؟
قُدّم StampedLock في Java 8، وهو يوسّع مفاهيم ReadWriteLock بوضع إضافي هو القراءة المتفائلة. وتُرجع العمليات طابعًا من النوع long يُستخدم لتحرير القفل أو للتحقق من صحة القراءة المتفائلة.
import java.util.concurrent.locks.*;
StampedLock sl = new StampedLock();
// Exclusive write:
long stamp = sl.writeLock();
try {
// write data
} finally {
sl.unlockWrite(stamp);
}
// Shared read:
stamp = sl.readLock();
try {
// read data
} finally {
sl.unlockRead(stamp);
}وضع القراءة المتفائلة
لا تحصل القراءة المتفائلة على أي قفل — بل تحصل على طابع فقط. وبعد القراءة، تحقّق من صحة الطابع. فإذا فشل التحقق (أي تدخّل كاتب)، فانتقل إلى قفل قراءة فعلي:
StampedLock sl2 = new StampedLock();
double x = 0, y = 0;
// Try optimistic read first:
long stamp = sl2.tryOptimisticRead();
double localX = x, localY = y; // read values
if (!sl2.validate(stamp)) {
// A write occurred — fall back to read lock
stamp = sl2.readLock();
try {
localX = x;
localY = y;
} finally {
sl2.unlockRead(stamp);
}
}
// use localX and localYمثال Point2D كامل
مثال تقليدي على StampedLock — نقطة ثنائية الأبعاد مع قراءات متفائلة:
class Point {
private double x, y;
private final StampedLock lock = new StampedLock();
void move(double dx, double dy) {
long stamp = lock.writeLock();
try { x += dx; y += dy; }
finally { lock.unlockWrite(stamp); }
}
double distanceFromOrigin() {
long stamp = lock.tryOptimisticRead();
double cx = x, cy = y;
if (!lock.validate(stamp)) {
stamp = lock.readLock();
try { cx = x; cy = y; }
finally { lock.unlockRead(stamp); }
}
return Math.sqrt(cx * cx + cy * cy);
}
}تحويل القفل
يدعم StampedLock التحويل بين أوضاع القفل:
StampedLock sl3 = new StampedLock();
// Read → Write upgrade attempt:
long readStamp = sl3.readLock();
long writeStamp = sl3.tryConvertToWriteLock(readStamp);
if (writeStamp != 0) {
// Successfully upgraded!
// ... write ...
sl3.unlockWrite(writeStamp);
} else {
// Upgrade failed — release read and reacquire write
sl3.unlockRead(readStamp);
writeStamp = sl3.writeLock();
// ... write ...
sl3.unlockWrite(writeStamp);
}متى تكون القراءات المتفائلة أكثر فائدة
تكون القراءات المتفائلة مفيدة جدًا عندما:
- تكون القراءات أكثر تكرارًا من الكتابات بفارق كبير
- تتسع لقطة البيانات في بضعة متغيرات محلية (من دون إنشاء كائنات)
- يكون تنازع الكتابة منخفضًا (لذلك نادرًا ما يفشل التحقق)
أما إذا كانت الكتابات متكررة، فستنتقل القراءات المتفائلة مرارًا إلى أقفال قراءة كاملة، ولن تقدم أي فائدة.
StampedLock مقابل ReadWriteLock
الاختلافات الأساسية:
- StampedLock: يضيف القراءات المتفائلة؛ وليس قابلًا لإعادة الدخول؛ ولا يدعم Condition
- ReentrantReadWriteLock: قابل لإعادة الدخول؛ ويدعم Conditions؛ ولا يوفر الوضع المتفائل
يكون StampedLock أسرع عند انخفاض تنازع الكتابة. أما ReentrantReadWriteLock فهو أكثر أمانًا وغنىً بالميزات.
StampedLock غير قابل لإعادة الدخول
بخلاف ReentrantLock، لا يُعد StampedLock قابلًا لإعادة الدخول. وسيؤدي أي خيط يحاول الحصول على وضع يحمله بالفعل إلى توقف تام:
StampedLock sl4 = new StampedLock();
long s1 = sl4.readLock();
// DO NOT: sl4.readLock() again — deadlocks with non-reentrant!tryWriteLock وtryReadLock
تُرجع محاولات الحصول على القفل دون حجب القيمة 0 عند الفشل:
StampedLock sl5 = new StampedLock();
long stamp = sl5.tryWriteLock();
if (stamp != 0) {
try {
System.out.println("Got write lock");
} finally {
sl5.unlockWrite(stamp);
}
} else {
System.out.println("Write lock unavailable");
}استخدامه كـ ReadWriteLock
يمكن لـ StampedLock إرجاع واجهة عرض باعتبارها ReadWriteLock قياسيًا للتوافق:
StampedLock sl6 = new StampedLock();
Lock readLock = sl6.asReadLock();
Lock writeLock = sl6.asWriteLock();
ReadWriteLock rwView = sl6.asReadWriteLock();
// These provide standard Lock interface without optimistic modeفهم معياري للأداء
تُظهر نتائج الاختبارات المعيارية عادةً ما يلي:
- أعباء العمل التي تهيمن فيها القراءات بشدة (99% قراءات): StampedLock > ReadWriteLock > synchronized
- أعباء العمل المختلطة (70% قراءات): ReadWriteLock ≈ StampedLock
- أعباء العمل التي تهيمن فيها الكتابات: غالبًا ما يتفوق synchronized أو ReentrantLock (بسبب التكلفة الأقل)
أجرِ دائمًا تحليلًا للأداء باستخدام أعباء عمل واقعية قبل التحسين.
بطلان الطابع بعد إلغاء القفل
بعد تحرير قفل باستخدام طابع، يصبح ذلك الطابع غير صالح. ويؤدي استخدام طابع قديم بعد إلغاء القفل إلى سلوك غير محدد — احرص دائمًا على التقاط طابع جديد مع كل عملية الحصول على القفل.
StampedLock sl7 = new StampedLock();
long stamp = sl7.writeLock();
sl7.unlockWrite(stamp);
// stamp is now invalid — don't use it:
// sl7.unlockWrite(stamp); // throws IllegalMonitorStateException or corrupts stateاختبار سريع
تُرجع قراءة متفائلة باستخدام tryOptimisticRead() يتبعها validate(stamp) القيمة false. ما الإجراء التالي الذي ينبغي أن ينفذه الكود؟
مراجعة: StampedLock
أهم النقاط:
- ثلاثة أوضاع: قراءة متفائلة (دون قفل) وقفل قراءة وقفل كتابة
- tryOptimisticRead() + validate() — محاولة قراءة بلا تكلفة تقريبًا
- عند فشل التحقق → انتقل إلى readLock()
- غير قابل لإعادة الدخول — خطر حدوث توقف تام إذا أعاد الخيط نفسه الحصول على القفل
- لا يدعم Condition — استخدم ReentrantReadWriteLock عند الحاجة
الأسئلة الشائعة
هل درس «StampedLock والقراءات المتفائلة» مجاني؟
نعم — نص درس «StampedLock والقراءات المتفائلة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Java Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Java Academy 4 دروس في المجموع.
ماذا ستتعلم في «StampedLock والقراءات المتفائلة»؟
طبّق وضع القراءة المتفائلة في StampedLock لأحمال العمل عالية الإنتاجية التي يغلب عليها القراءة تتمرن على Java Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Java Academy؟
لا تُشترط خبرة سابقة. Java Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.
كم من الوقت يستغرق درس «StampedLock والقراءات المتفائلة»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Java Academy هذا؟
نعم. كل درس في Java Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- ReentrantLock مقابل synchronized
- ReadWriteLock لسيناريوهات القارئ والكاتب
- المتغيرات الذرية: تحديثات دون أقفال
- StampedLock والقراءات المتفائلة