في يوم الجمعة وعطلة نهاية الأسبوع الماضيين، أخذت استراحة من عملي المزدحم وراجعت تنفيذ Thread.interrupt وLockSupport بعد Java 5 أثناء مشاهدة Java cocurrent.
قبل أن أقدم لكم، اسمحوا لي أن أطرح بعض الأسئلة.
ما هي العلاقة بين طريقة Thread.interrupt() و InterruptedException؟ هل يتم تشغيل استثناء InterruptedException بواسطة المقاطعة؟
في أي حالة سوف يقوم Thread.interrupt() بمقاطعة عمل الخيط؟ تشغيل أو حظر؟
هل تحتاج برمجة الخيوط العامة إلى الاهتمام بالمقاطعات؟ كيفية التعامل معها بشكل عام؟ ما الذي يمكن استخدامه؟
ما الفرق بين LockSupport.park() وunpark() وobject.wait() وnotify()؟
ما فائدة كائن الحظر الذي تم تمريره بواسطة LockSupport.park (حاجب الكائنات)؟
هل يمكن لـ LockSupport الاستجابة لأحداث Thread.interrupt()؟ هل سيتم طرح InterruptedException؟
هل هناك وظيفة رد اتصال مقابلة لمعالجة Thread.interrupt()؟ شيء من هذا القبيل مكالمة هوك؟
إذا تمكنت من الإجابة على كل شيء بوضوح، فهذا يعني أنك تفهم تمامًا Thread.interrupt، ولن تحتاج إلى مزيد من القراءة.
إذا كنت لا تزال غير واضح، فلنحل هذه الأسئلة معًا.
عدة طرق للتعامل مع مقاطعة الموضوع:
مقاطعة الفراغ العام (): تنفيذ حدث مقاطعة مؤشر الترابط
public boolean isInterrupted(): تحقق مما إذا كان مؤشر الترابط الحالي قد تمت مقاطعته
تمت مقاطعة منطقية ثابتة عامة (): تحقق مما إذا كان مؤشر الترابط الحالي قد تمت مقاطعته وأعد تعيين معلومات المقاطعة. مشابهة لـ إعادة تعيينAndGet()
يفهم:
1. يحتوي كل مؤشر ترابط على علامة حالة مقاطعة للإشارة إلى ما إذا كان مؤشر الترابط الحالي في حالة مقاطعة.
2. بشكل عام، هناك طريقتان للمعالجة عند استدعاء Thread.interrupt() عند مواجهة حالة كتلة ذات أولوية منخفضة، مثل object.wait()، object.sleep()، object.join(). سيؤدي ذلك على الفور إلى إطلاق عملية إلغاء الحظر لإلغاء الحظر ورمي InterruptedException.
في حالات أخرى، يقوم Thread.interrupt() فقط بتحديث إشارة الحالة. ثم يتحقق مؤشر ترابط العامل الخاص بك من خلال Thread.isInterrrupted() ويمكنه إجراء المعالجة المقابلة، مثل طرح InterruptedException أو مسح الحالة، وإلغاء المهمة، وما إلى ذلك.
الموصوفة في مقاطعة javadoc:
أفضل الممارسات
هناك مقالة عن IBM جيدة جدًا. نظرية وممارسة جافا: التعامل مع InterruptedException، الذي يذكر العديد من أفضل الممارسات للتعامل مع المقاطعة.
لا تبتلع المقاطعات (لا تأكل المقاطعة، هناك نوعان من المعالجة بشكل عام: الاستمرار في طرح InterruptedException. والآخر هو الاستمرار في تعيين علامة استثناء Thread.interupt()، مما يسمح للمستوى الأعلى بالتعامل معها وفقًا لذلك).
انسخ رمز الكود كما يلي:
فئة عامة TaskRunner تنفذ Runnable {
قائمة انتظار BlockingQueue<Task> الخاصة؛
عامة TaskRunner(BlockingQueue<Task> queue) {
this.queue = queue;
}
تشغيل الفراغ العام () {
يحاول {
بينما (صحيح) {
مهمة المهمة = queue.take(10, TimeUnit.SECONDS);
Task.execute();
}
}
قبض على (InterruptedException ه) {
// استعادة حالة المقاطعة
Thread.currentThread().interrupt();
}
}
}
انسخ رمز الكود كما يلي:
فئة عامة TaskRunner تنفذ Runnable {
قائمة انتظار BlockingQueue<Task> الخاصة؛
عامة TaskRunner(BlockingQueue<Task> queue) {
this.queue = queue;
}
تشغيل الفراغ العام () {
يحاول {
بينما (صحيح) {
مهمة المهمة = queue.take(10, TimeUnit.SECONDS);
Task.execute();
}
}
قبض على (InterruptedException ه) {
// استعادة حالة المقاطعة
Thread.currentThread().interrupt();
}
}
}
تنفيذ المهام القابلة للإلغاء باستخدام Interrupt (استخدم Thread.interrupt() لتصميم ودعم المهام التي يمكن إلغاؤها)
انسخ رمز الكود كما يلي:
الطبقة العامة PrimeProducer تمتد الموضوع {
قائمة انتظار BlockingQueue<BigInteger> النهائية الخاصة؛
PrimeProducer(BlockingQueue<BigInteger> queue) {
this.queue = queue;
}
تشغيل الفراغ العام () {
يحاول {
BigInteger p = BigInteger.ONE;
بينما (!Thread.currentThread().isInterrupted())
queue.put(p = p.nextProbablePrime());
} قبض (تم استهلاك InterruptedException) {
/* السماح للخيط بالخروج */
}
}
public void Cancel() {rupt(); } // بدء المقاطعة
}<SPAN style="WHITE-SPACE: Normal"> </SPAN>
انسخ رمز الكود كما يلي:
الطبقة العامة PrimeProducer تمتد الموضوع {
قائمة انتظار BlockingQueue<BigInteger> النهائية الخاصة؛
PrimeProducer(BlockingQueue<BigInteger> queue) {
this.queue = queue;
}
تشغيل الفراغ العام () {
يحاول {
BigInteger p = BigInteger.ONE;
بينما (!Thread.currentThread().isInterrupted())
queue.put(p = p.nextProbablePrime());
} قبض (تم استهلاك InterruptedException) {
/* السماح للخيط بالخروج */
}
}
public void Cancel() {rupt(); } // بدء المقاطعة
}<SPAN style="WHITE-SPACE: Normal"> </SPAN>
تسجيل حدث معالجة المقاطعة (استخدام غير طبيعي)
بشكل عام، تم تصميم المهام العادية للتعامل مع الإلغاء، وتستخدم جميعها الاستقصاء النشط للتحقق من Thread.isInterrupt()، الذي يحتوي على درجة معينة من الدمج في العمل نفسه، وهناك أيضًا تأخير يجب عليك الانتظار حتى التالي نقطة تفتيش (من يعرف متى تكون نقطة التفتيش التالية؟ خاصة عند إجراء مأخذ توصيل. قراءة، واجهت مشكلة انتهاء مهلة HttpClient).
دعونا نلقي نظرة. يعتمد تنفيذ رمي InterruptedException على تصميم InterruptibleChannel، وهو ذكي جدًا.
انسخ رمز الكود كما يلي:
واجهة InterruptAble { // تحديد واجهة قابلة للمقاطعة
مقاطعة الفراغ العام () تطرح InterruptedException؛
}
فئة مجردة InterruptSupport تنفذ InterruptAble {
منطقية متطايرة خاصة تمت مقاطعتها = خطأ؛
مقاطعة خاصة قابلة للمقاطعة = مقاطعة جديدة () {
مقاطعة الفراغ العام () {
متقطع = صحيح؛
InterruptSupport.this.interrupt(); // الموضع 3
}
};
تنفيذ منطقي نهائي عام () يلقي InterruptedException {
يحاول {
blockedOn(interruptor);// الموضع 1
إذا (Thread.currentThread().isInterrupted()) { // تمت مقاطعته على الفور
Interruptor.interrupt();
}
// تنفيذ كود العمل
عمل();
} أخيراً {
blockedOn(null);
}
انقطعت العودة؛
}
الملخص العام باطلة الأعمال () ؛
مقاطعة باطلة مجردة عامة () ؛
// -- sun.misc.SharedSecrets --
static void blockedOn(Interruptible intr) { // package-private
sun.misc.SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(), intr);
}
}
انسخ رمز الكود كما يلي:
واجهة InterruptAble { // تحديد واجهة قابلة للمقاطعة
مقاطعة الفراغ العام () تطرح InterruptedException؛
}
فئة مجردة InterruptSupport تنفذ InterruptAble {
منطقية متطايرة خاصة تمت مقاطعتها = خطأ؛
مقاطعة خاصة قابلة للمقاطعة = مقاطعة جديدة () {
مقاطعة الفراغ العام () {
متقطع = صحيح؛
InterruptSupport.this.interrupt(); // الموضع 3
}
};
تنفيذ منطقي نهائي عام () يلقي InterruptedException {
يحاول {
blockedOn(interruptor);// الموضع 1
إذا (Thread.currentThread().isInterrupted()) { // تمت مقاطعته على الفور
Interruptor.interrupt();
}
// تنفيذ كود العمل
عمل();
} أخيراً {
blockedOn(null);
}
انقطعت العودة؛
}
الملخص العام باطلة الأعمال () ؛
مقاطعة باطلة مجردة عامة () ؛
// -- sun.misc.SharedSecrets --
static void blockedOn(Interruptible intr) { // package-private
sun.misc.SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(), intr);
}
}
وصف الكود، بعض الحيل:
الموضع 1: استخدم طريقة blockOn التي توفرها الشمس لربط ربط معالجة الحدث القابل للمقاطعة المقابل بالخيط المحدد.
الموضع 2: بعد تنفيذ التعليمات البرمجية، قم بمسح الخطاف. تجنب التأثير على حدث معالجة الخيط التالي عند استخدام تجمع الاتصال.
الموضع 3: يحدد طريقة معالجة ربط الحدث القابل للمقاطعة ويعيد استدعاء أسلوب InterruptSupport.this.interrupt(). يمكن للفئات الفرعية دمج وتنفيذ منطق الأعمال الخاص بها، مثل إغلاق تيار الجورب، وما إلى ذلك.
يستخدم:
انسخ رمز الكود كما يلي:
فئة InterruptRead تمتد InterruptSupport {
FileInputStream الخاص في؛
@تجاوز
الأعمال التجارية باطلة العامة () {
File file = new File("/dev/urandom"); // اقرأ الثقب الأسود لنظام Linux، ولا تنتهي من القراءة أبدًا
يحاول {
in = new FileInputStream(file);
بايت[] بايت = بايت جديد[1024];
بينما (in.read(bytes, 0, 1024) > 0) {
// Thread.sleep(100);
// if (Thread.interrupted()) {// طريقة التحقق من المقاطعة السابقة
// طرح InterruptedException الجديد("");
// }
}
} قبض (الاستثناء ه) {
رمي RuntimeException (e) الجديد ؛
}
}
public FileInputStream getIn() {
العودة في؛
}
@تجاوز
مقاطعة الفراغ العام () {
يحاول {
in.getChannel().إغلاق();
} قبض (IOException ه) {
printStackTrace();
}
}
}
public static void main(String args[]) يطرح الاستثناء {
اختبار InterruptRead النهائي = New InterruptRead();
الموضوع ر = الموضوع الجديد () {
@تجاوز
تشغيل الفراغ العام () {
بداية طويلة = System.currentTimeMillis();
يحاول {
System.out.println("بدء مقاطعة القراءة!");
test.execute();
} قبض على (InterruptedException e) {
System.out.println("نهاية InterruptRead! وقت التكلفة:" + (System.currentTimeMillis() - start));
printStackTrace();
}
}
};
t.start();
// دع القراءة تنفذ لمدة 3 ثوانٍ أولاً
Thread.sleep(3000);
// إصدار مقاطعة
t.interrupt();
}
انسخ رمز الكود كما يلي:
فئة InterruptRead تمتد InterruptSupport {
FileInputStream الخاص في؛
@تجاوز
الأعمال التجارية باطلة العامة () {
File file = new File("/dev/urandom"); // اقرأ الثقب الأسود لنظام Linux، ولا تنتهي من القراءة أبدًا
يحاول {
in = new FileInputStream(file);
بايت[] بايت = بايت جديد[1024];
بينما (in.read(bytes, 0, 1024) > 0) {
// Thread.sleep(100);
// if (Thread.interrupted()) {// طريقة التحقق من المقاطعة السابقة
// طرح InterruptedException الجديد("");
// }
}
} قبض (الاستثناء ه) {
رمي RuntimeException (e) الجديد ؛
}
}
public FileInputStream getIn() {
العودة في؛
}
@تجاوز
مقاطعة الفراغ العام () {
يحاول {
in.getChannel().إغلاق();
} قبض (IOException ه) {
printStackTrace();
}
}
}
public static void main(String args[]) يطرح الاستثناء {
اختبار InterruptRead النهائي = New InterruptRead();
الموضوع ر = الموضوع الجديد () {
@تجاوز
تشغيل الفراغ العام () {
بداية طويلة = System.currentTimeMillis();
يحاول {
System.out.println("بدء مقاطعة القراءة!");
test.execute();
} قبض على (InterruptedException e) {
System.out.println("نهاية InterruptRead! وقت التكلفة:" + (System.currentTimeMillis() - start));
printStackTrace();
}
}
};
t.start();
// دع القراءة تنفذ لمدة 3 ثوانٍ أولاً
Thread.sleep(3000);
// إصدار مقاطعة
t.interrupt();
}
مقدمة كود مصدر Jdk:
1. يمكن للخطاف الذي توفره الشمس عرض كود النظام ذي الصلة، السطر: 1125
انسخ رمز الكود كما يلي:
sun.misc.SharedSecrets.setJavaLangAccess(new sun.misc.JavaLangAccess(){
public sun.reflect.ConstantPool getConstantPool(Class klass) {
إرجاع klass.getConstantPool();
}
public void setAnnotationType(Class klass, AnnotationType type) {
klass.setAnnotationType(type);
}
نوع التعليق التوضيحي العام getAnnotationType(Class klass) {
إرجاع klass.getAnnotationType();
}
عام <E يمتد التعداد<E>>
E[] getEnumConstantsShared(Class<E> klass) {
إرجاع klass.getEnumConstantsShared();
}
الفراغ العام المحظور (Thread t، Interruptible b) {
t.blockedOn(b);
}
});
انسخ رمز الكود كما يلي:
sun.misc.SharedSecrets.setJavaLangAccess(new sun.misc.JavaLangAccess(){
public sun.reflect.ConstantPool getConstantPool(Class klass) {
إرجاع klass.getConstantPool();
}
public void setAnnotationType(Class klass, AnnotationType type) {
klass.setAnnotationType(type);
}
نوع التعليق التوضيحي العام getAnnotationType(Class klass) {
إرجاع klass.getAnnotationType();
}
عام <E يمتد التعداد<E>>
E[] getEnumConstantsShared(Class<E> klass) {
إرجاع klass.getEnumConstantsShared();
}
الفراغ العام المحظور (Thread t، Interruptible b) {
t.blockedOn(b);
}
});
2. الموضوع. المقاطعة ()
انسخ رمز الكود كما يلي:
مقاطعة الفراغ العام () {
إذا (هذا!= Thread.currentThread())
checkAccess();
متزامن (blockerLock) {
قابل للمقاطعة ب = مانع؛
إذا (ب ! = فارغة) {
Interrupt0(); // فقط لتعيين علامة المقاطعة
b.interrupt(); // خطاف رد الاتصال
يعود؛
}
}
المقاطعة0();
}
انسخ رمز الكود كما يلي:
مقاطعة الفراغ العام () {
إذا (هذا!= Thread.currentThread())
checkAccess();
متزامن (blockerLock) {
قابل للمقاطعة ب = مانع؛
إذا (ب ! = فارغة) {
Interrupt0(); // فقط لتعيين علامة المقاطعة
b.interrupt(); // خطاف رد الاتصال
يعود؛
}
}
المقاطعة0();
}
لمزيد من المعلومات حول استخدام Thread.stop والتعليق والاستئناف والمقاطعة، يمكنك إلقاء نظرة على وثائق Sun، مثل http://download.Oracle.com/javase/6/docs/technotes/guides/concurrency /threadPrimitiveDeprecation .html
وأخيرا دعونا نجيب على بعض الأسئلة السابقة:
السؤال 1: ما هي العلاقة بين طريقة Thread.interrupt() وInterruptedException؟ هل يتم تشغيل استثناء InterruptedException بواسطة المقاطعة؟
الإجابة: سوف يقوم Thread.interrupt() بطرح InterruptedException بشكل فعال فقط في Object.wait() و.Object.join() وObject.sleep(). وهو أمر شائع في الكتل الأخرى، فقط عن طريق تعيين معلومات إشارة للخيط، ويحتاج البرنامج إلى معالجتها بنفسه.
انسخ رمز الكود كما يلي:
إذا (Thread.interrupt()) // يمسح حالة المقاطعة!
رمي InterruptedException () الجديد ؛
انسخ رمز الكود كما يلي:
إذا (Thread.interrupt()) // يمسح حالة المقاطعة!
رمي InterruptedException () الجديد ؛
السؤال 2: في أي حالة سوف يقوم Thread.interrupt() بمقاطعة عمل الخيط؟ تشغيل أو حظر؟
الإجابة: الغرض من تصميم Thread.interrupt هو بشكل أساسي التعامل مع سلاسل الرسائل في حالة الكتلة، مثل حالات الانتظار () والنوم (). ومع ذلك، يمكن دعم إلغاء المهام أثناء تصميم البرنامج، ويمكن أيضًا دعم حالة التشغيل. على سبيل المثال، Object.join() وبعض تصميمات قنوات nio التي تدعم المقاطعة.
السؤال 3: هل تحتاج برمجة الخيوط العامة إلى الاهتمام بالمقاطعات؟ كيفية التعامل معها بشكل عام؟ ما الذي يمكن استخدامه؟
الإجابة: استخدام المقاطعة: إلغاء الحظر، ودعم إلغاء المهام، وتنظيف البيانات، وما إلى ذلك.
السؤال 4: ما الفرق بين LockSupport.park() وunpark() وobject.wait() وnotify()؟
إجابة:
1. المواضيع مختلفة. يقوم LockSuport بشكل أساسي بإجراء معالجة الحظر لـ Thread، ويمكنه تحديد الكائن الهدف لقائمة انتظار الحظر وتحديد مؤشر ترابط معين للتنبيه في كل مرة. يأخذ Object.wait() الكائن باعتباره البعد، ويحظر الخيط الحالي وينشط خيطًا واحدًا (عشوائيًا) أو كل سلاسل الرسائل.
2. آليات التنفيذ مختلفة. على الرغم من أن LockSuport يمكنه تحديد كائن الكائن للشاشة، إلا أن قوائم الانتظار المحظورة الخاصة بـ LockSuport وobject.wait() لا تتقاطع. يمكنك إلقاء نظرة على مثال الاختبار. لا يمكن لـ object.notifyAll() تنبيه مؤشر ترابط LockSupport المحظور.
السؤال 5: ما فائدة كائن الحظر الذي تم تمريره بواسطة LockSupport.park(حاجب الكائنات)؟
الإجابة: سيتم تسجيل blcoker المقابل في سمة parkBlocker الخاصة بـ Thread. ومن السهل جدًا مراقبة كائنات حظر معينة من خلال أمر jstack.
انسخ رمز الكود كما يلي:
متنزه الفراغ الثابت العام (حاجب الكائنات) {
الموضوع t = Thread.currentThread();
setBlocker(t, blocker); // قم بتعيين قيمة خاصية Thread.parkBlocker
unsafe.park(false, 0L);
setBlocker(t, null); // امسح قيمة خاصية Thread.parkBlocker
}
انسخ رمز الكود كما يلي:
متنزه الفراغ الثابت العام (حاجب الكائنات) {
الموضوع t = Thread.currentThread();
setBlocker(t, blocker); // قم بتعيين قيمة خاصية Thread.parkBlocker
unsafe.park(false, 0L);
setBlocker(t, null); // امسح قيمة خاصية Thread.parkBlocker
}
وصف javadoc المحدد لـ LockSupport واضح نسبيًا أيضًا، ويمكنك قراءته أدناه:
السؤال 6: هل يمكن لـ LockSupport الاستجابة لأحداث Thread.interrupt()؟ هل سيتم طرح InterruptedException؟
الإجابة: يمكنه الاستجابة لأحداث المقاطعة، لكنه لن يطرح InterruptedException. فيما يتعلق بدعم LockSupport لـ Thread.interrupt، قم أيضًا بإلقاء نظرة على الوصف الموجود في javadoc:
رمز الاختبار ذات الصلة
انسخ رمز الكود كما يلي:
package com.agapple.cocurrent;
استيراد java.io.File؛
استيراد java.io.FileInputStream؛
import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
الطبقة العامة LockSupportTest {
مانع LockSupportTest الخاص الثابت = new LockSupportTest();
public static void main(String args[]) يطرح الاستثناء {
lockSupportTest();
parkTest();
IntertParkTest();
مقاطعةSleepTest();
InterruptWaitTest();
}
/**
* بعد كائن LockSupport.park، حاول الحصول على كائن Thread.blocker واستدعاء التنبيه الفردي الخاص به
*
* @throwsException
*/
قفل الفراغ الثابت الخاصSupportTest() يلقي استثناء {
الموضوع t = doTest(new TestCallBack() {
@تجاوز
رد الاتصال العام الفارغ () يلقي الاستثناء {
// حاول النوم 5S
System.out.println("blocker");
LockSupport.park(blocker);
System.out.println("استيقظ الآن!");
}
@تجاوز
سلسلة عامة getName () {
إرجاع "lockSupportTest"؛
}
});
t.start(); // ابدأ موضوع القراءة
Thread.sleep(150);
متزامن (مانع) {
حقل الحقل = Thread.class.getDeclaredField("parkBlocker");
field.setAccessible(true);
Object fBlocker = field.get(t);
System.out.println(blocker == fBlocker);
Thread.sleep(100);
System.out.println("notifyAll");
blocker.notifyAll();
}
}
/**
* إذا حاولت مقاطعة object.wait()، فسيتم طرح InterruptedException المطابق.
*
* @throws InterruptedException
*/
مقاطعة باطلة ثابتة خاصة () تطرح InterruptedException {
الكائن النهائي obj = كائن جديد ()؛
الموضوع t = doTest(new TestCallBack() {
@تجاوز
رد الاتصال العام الفارغ () يلقي الاستثناء {
// حاول النوم 5S
obj.wait();
System.out.println("استيقظ الآن!");
}
@تجاوز
سلسلة عامة getName () {
إرجاع "interruptWaitTest"؛
}
});
t.start(); // ابدأ موضوع القراءة
Thread.sleep(2000);
t.interrupt(); // التحقق من الاستجابة للمقاطعة أثناء الإيقاف
}
/**
* إذا حاولت مقاطعة Thread.sleep()، فسيتم طرح InterruptedException المطابق.
*
* @throws InterruptedException
*/
مقاطعة باطلة ثابتة خاصة () تطرح InterruptedException {
الموضوع t = doTest(new TestCallBack() {
@تجاوز
رد الاتصال العام الفارغ () يلقي الاستثناء {
// حاول النوم 5S
Thread.sleep(5000);
System.out.println("استيقظ الآن!");
}
@تجاوز
سلسلة عامة getName () {
إرجاع "interruptSleepTest"؛
}
});
t.start(); // ابدأ موضوع القراءة
Thread.sleep(2000);
t.interrupt(); // التحقق من الاستجابة للمقاطعة أثناء الإيقاف
}
/**
* حاول مقاطعة LockSupport.park()، ستكون هناك استجابة ولكن لن يتم طرح استثناء InterruptedException
*
* @throws InterruptedException
*/
مقاطعة باطلة ثابتة خاصة () يلقي InterruptedException {
الموضوع t = doTest(new TestCallBack() {
@تجاوز
رد الاتصال العام الفارغ () {
// حاول إيقاف موضوعك الخاص
LockSupport.parkNanos(blocker, TimeUnit.SECONDS.toNanos(5));
System.out.println("استيقظ الآن!");
}
@تجاوز
سلسلة عامة getName () {
إرجاع "interruptParkTest"؛
}
});
t.start(); // ابدأ موضوع القراءة
Thread.sleep(2000);
t.interrupt(); // التحقق من الاستجابة للمقاطعة أثناء الإيقاف
}
/**
* حاول مقاطعة LockSupport.unPark()، سيكون هناك رد
*
* @throws InterruptedException
*/
يلقي parkTest () الفراغ الثابت الخاص InterruptedException {
الموضوع t = doTest(new TestCallBack() {
@تجاوز
رد الاتصال العام الفارغ () {
// حاول إيقاف موضوعك الخاص
LockSupport.park(blocker);
System.out.println("استيقظ الآن!");
}
@تجاوز
سلسلة عامة getName () {
إرجاع "parkTest" ؛
}
});
t.start(); // ابدأ موضوع القراءة
Thread.sleep(2000);
LockSupport.unpark(t);
t.interrupt();
}
مؤشر ترابط عام ثابت doTest (استدعاء TestCallBack النهائي) {
إرجاع موضوع جديد () {
@تجاوز
تشغيل الفراغ العام () {
File file = new File("/dev/urandom"); // قراءة الثقب الأسود في Linux
يحاول {
FileInputStream in = new FileInputStream(file);
بايت[] بايت = بايت جديد[1024];
بينما (in.read(bytes, 0, 1024) > 0) {
إذا (Thread.interrupt()) {
رمي InterruptedException("");
}
System.out.println(بايت[0]);
Thread.sleep(100);
بداية طويلة = System.currentTimeMillis();
call.callback();
System.out.println(call.getName() + "تكلفة إنهاء رد الاتصال:"
+ (System.currentTimeMillis() - start));
}
} قبض (الاستثناء ه) {
printStackTrace();
}
}
};
}
}
واجهة اختبار CallBack {
رد الاتصال باطلة عامة () يلقي استثناء؛
سلسلة عامة getName();
}
انسخ رمز الكود كما يلي:
package com.agapple.cocurrent;
استيراد java.io.File؛
استيراد java.io.FileInputStream؛
import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
الطبقة العامة LockSupportTest {
مانع LockSupportTest الخاص الثابت = new LockSupportTest();
public static void main(String args[]) يطرح الاستثناء {
lockSupportTest();
parkTest();
IntertParkTest();
مقاطعةSleepTest();
InterruptWaitTest();
}
/**
* بعد كائن LockSupport.park، حاول الحصول على كائن Thread.blocker واستدعاء التنبيه الفردي الخاص به
*
* @throwsException
*/
قفل الفراغ الثابت الخاصSupportTest() يلقي استثناء {
الموضوع t = doTest(new TestCallBack() {
@تجاوز
رد الاتصال العام الفارغ () يلقي الاستثناء {
// حاول النوم 5S
System.out.println("blocker");
LockSupport.park(blocker);
System.out.println("استيقظ الآن!");
}
@تجاوز
سلسلة عامة getName () {
إرجاع "lockSupportTest"؛
}
});
t.start(); // ابدأ موضوع القراءة
Thread.sleep(150);
متزامن (مانع) {
حقل الحقل = Thread.class.getDeclaredField("parkBlocker");
field.setAccessible(true);
Object fBlocker = field.get(t);
System.out.println(blocker == fBlocker);
Thread.sleep(100);
System.out.println("notifyAll");
blocker.notifyAll();
}
}
/**
* إذا حاولت مقاطعة object.wait()، فسيتم طرح InterruptedException المقابل.
*
* @throws InterruptedException
*/
مقاطعة باطلة ثابتة خاصة () تطرح InterruptedException {
الكائن النهائي obj = كائن جديد ()؛
الموضوع t = doTest(new TestCallBack() {
@تجاوز
رد الاتصال العام الفارغ () يلقي الاستثناء {
// حاول النوم 5S
obj.wait();
System.out.println("استيقظ الآن!");
}
@تجاوز
سلسلة عامة getName () {
إرجاع "interruptWaitTest"؛
}
});
t.start(); // ابدأ موضوع القراءة
Thread.sleep(2000);
t.interrupt(); // التحقق من الاستجابة للمقاطعة أثناء الإيقاف
}
/**
* إذا حاولت مقاطعة Thread.sleep()، فسيتم طرح InterruptedException المطابق.
*
* @throws InterruptedException
*/
مقاطعة باطلة ثابتة خاصة () تطرح InterruptedException {
الموضوع t = doTest(new TestCallBack() {
@تجاوز
رد الاتصال العام الفارغ () يلقي الاستثناء {
// حاول النوم 5S
Thread.sleep(5000);
System.out.println("استيقظ الآن!");
}
@تجاوز
سلسلة عامة getName () {
إرجاع "interruptSleepTest"؛
}
});
t.start(); // ابدأ موضوع القراءة
Thread.sleep(2000);
t.interrupt(); // التحقق من الاستجابة للمقاطعة أثناء الإيقاف
}
/**
* حاول مقاطعة LockSupport.park()، ستكون هناك استجابة ولكن لن يتم طرح استثناء InterruptedException
*
* @throws InterruptedException
*/
مقاطعة باطلة ثابتة خاصة () يلقي InterruptedException {
الموضوع t = doTest(new TestCallBack() {
@تجاوز
رد الاتصال العام الفارغ () {
// حاول إيقاف موضوعك الخاص
LockSupport.parkNanos(blocker, TimeUnit.SECONDS.toNanos(5));
System.out.println("استيقظ الآن!");
}
@تجاوز
سلسلة عامة getName () {
إرجاع "interruptParkTest"؛
}
});
t.start(); // ابدأ موضوع القراءة
Thread.sleep(2000);
t.interrupt(); // التحقق من الاستجابة للمقاطعة أثناء الإيقاف
}
/**
* حاول مقاطعة LockSupport.unPark()، سيكون هناك رد
*
* @throws InterruptedException
*/
يلقي parkTest () الفراغ الثابت الخاص InterruptedException {
الموضوع t = doTest(new TestCallBack() {
@تجاوز
رد الاتصال العام الفارغ () {
// حاول إيقاف موضوعك الخاص
LockSupport.park(blocker);
System.out.println("استيقظ الآن!");
}
@تجاوز
سلسلة عامة getName () {
إرجاع "parkTest" ؛
}
});
t.start(); // ابدأ موضوع القراءة
Thread.sleep(2000);
LockSupport.unpark(t);
t.interrupt();
}
مؤشر ترابط عام ثابت doTest (استدعاء TestCallBack النهائي) {
إرجاع موضوع جديد () {
@تجاوز
تشغيل الفراغ العام () {
File file = new File("/dev/urandom"); // قراءة الثقب الأسود في Linux
يحاول {
FileInputStream in = new FileInputStream(file);
بايت[] بايت = بايت جديد[1024];
بينما (in.read(bytes, 0, 1024) > 0) {
إذا (Thread.interrupt()) {
رمي InterruptedException("");
}
System.out.println(بايت[0]);
Thread.sleep(100);
بداية طويلة = System.currentTimeMillis();
call.callback();
System.out.println(call.getName() + "تكلفة إنهاء رد الاتصال:"
+ (System.currentTimeMillis() - start));
}
} قبض (الاستثناء ه) {
printStackTrace();
}
}
};
}
}
واجهة اختبار CallBack {
رد الاتصال باطلة عامة () يلقي استثناء؛
سلسلة عامة getName();
}
أخيرًا <BR>لقد وجدت أن المقالة أصبحت أطول فأطول، لذلك قمت ببساطة بنشرها في المنتدى ليناقشها الجميع معًا، بعد كل شيء، وصفت المقالة فقط بعض الأشياء على مستوى الاستخدام، ولم تقدم موضوعًا من التشغيل بالنسبة لبعض الآليات، يمكن لـ Daniumen الذين هم على دراية بهذا المجال التعبير عن آرائهم.