0. فيما يتعلق بمزامنة الخيط (1) لماذا نحتاج إلى تزامن التعدد؟
يشير مزامنة الموضوع إلى السماح لخيوط التشغيل المتعددة بالتعاون بشكل جيد معًا للسماح لخيوط متعددة بتشغيل الموارد وإطلاقها بشكل معقول كما هو مطلوب. نستخدم كتل رمز التزامن وطرق المزامنة في Java لتحقيق هذا الهدف. على سبيل المثال ، قم بحل مشكلة تنفيذ الطلب غير المستقل متعدد الخيوط:
الفئة العامة twothReadTest {public static void main (string [] args) {thread th1 = new MyThread1 () ؛ الموضوع Th2 = جديد mythread2 () ؛ th1.start () ؛ Th2.start () ؛ }} class myThread2 يمتد Thread {Override public void run () {for (int i = 0 ؛ i <10 ؛ i ++). Out.println ("Thread 1 Counter:"+i) ؛ }} class myThread1 يمتد Thread {Override public void run () {for (int i = 0 ؛ i <10 ؛ i ++). Out.println ("Thread 1 Counter:"+i) ؛ }} class myThread1 يمتد Thread {Override public void run () {for (int i = 0 ؛ i <10 ؛ i ++). Out.println ("Thread 2 Counter:"+i) ؛ }}تتمثل نتيجة التنفيذ متعدد الخيوط في هذه الحالة في إدراج تنفيذ بشكل عشوائي في الإرادة ، والذي يعتمد كليا على جدولة مؤشر ترابط JVM. في كثير من الحالات التي يكون فيها التنفيذ المنظم مطلوبًا ، من الواضح أن حالة التنفيذ العشوائية هذه غير مناسبة.
الفئة العامة twhertest {public static void main (string [] args) {mythread thread = new MyThread () ؛ الموضوع Th1 = موضوع جديد (موضوع) ؛ الموضوع Th2 = مؤشر ترابط جديد (موضوع) ؛ th1.start () ؛ Th2.start () ؛ }} class mythread تنفذ Runnable {Override Public Synchronized void run () {for (int i = 0 ؛ i <10 ؛ i ++). Out.println (موضوع. CurrentThread (). getName ()+"Counter:"+i) ؛ }}بعد استخدام طريقة التزامن ، يمكننا التحكم في مؤشر الترابط ليشغل كائن جسم التنفيذ بشكل حصري. وبهذه الطريقة ، أثناء عملية التنفيذ ، يمكن لخيط تنفيذ المهام على هيئة التنفيذ في وقت واحد والخروج من حالة القفل. يقوم JVM بعد ذلك بإرسال مؤشر ترابط آخر لتشغيل المهام في هيئة التنفيذ في وقت واحد.
(2) نموذج إنشاء الخيط وتشغيله:
في الماضي ، كان لدينا أيضًا نموذج البرمجة الخاص بنا لإنشاء الخيط وتشغيله. بشكل عام ، حددنا فئة التنفيذ لإعادة كتابة طريقة Run () ، لكن هذه الطريقة تضع هيئة التنفيذ والمهام المنفذة معًا ، والتي لا تؤدي إلى فصلها عن منظور هندسة البرمجيات. يعني تنفيذ مؤشر ترابط أن مؤشر ترابط ينفذ مهمة كائن من خلال كائن التنفيذ. من هذا المنظور ، يمكن أن يؤدي فصل الواصفات الخاصة بالمهمة عن فئة التنفيذ إلى جعل الأدوار المختلفة للبرمجة متعددة الخيوط واضحة وبالتالي الحصول على فصل جيد. فيما يلي نموذج البرمجة لإنشاء وتنفيذ مؤشرات الترابط:
الفئة العامة الرسمية {public static void main (string [] args) {thread thread = new thread (new myrunnable ()) ؛ thread.start () ؛ }} class myrunnable تنفس Runnable {myTask myTask = new MyTask () ؛ Override public void run () {mytask.dotask () ؛ }} class myTask {public void dotask () {system. Out.println ("هذه مهمة حقيقية") ؛ }}
1. مبدأ متزامن
في Java ، يحتوي كل كائن على قفل التزامن واحد فقط. هذا يعني أيضًا أن قفل المزامنة موجود على الكائن.
عندما نسمي الطريقة المتزامنة لكائن ما ، فإننا نحصل على قفل المزامنة للكائن. على سبيل المثال ، يكتسب Synchronized (OBJ) قفل المزامنة لكائن OBJ ".
إن الوصول إلى أقفال التزامن بواسطة مؤشرات ترابط مختلفة هو حصري بشكل متبادل. بمعنى آخر ، في مرحلة معينة من الوقت ، لا يمكن الحصول على قفل تزامن الكائن إلا بواسطة مؤشر ترابط واحد! من خلال أقفال التزامن ، يمكننا تحقيق الوصول الحصري بشكل متبادل إلى "الكائنات/الأساليب" في مؤشرات ترابط متعددة. على سبيل المثال ، يوجد الآن موضوعان A و Thread B ، والذي يصل كلاهما إلى "قفل متزامن للكائن OBJ". لنفترض أنه في مرحلة ما ، يكتسب Thread A "قفل مزامنة OBJ" ويؤدي بعض العمليات ؛ في هذا الوقت ، يحاول الخيط B أيضًا الحصول على "قفل مزامنة OBJ" - سيفشل الخيط B في الحصول عليه ، ويجب أن ينتظر حتى يتم تصوير "قفل مزامنة OBJ" ويمكن تشغيله فقط.
2. القواعد الأساسية المتزامنة
نلخص القواعد الأساسية للمزامنة في الـ 3 التالية وتوضيحها من خلال أمثلة.
المادة 1: عندما يصل مؤشر ترابط إلى "الطريقة المتزامنة" أو "كتلة رمز متزامنة" من "كائن معين" ، سيتم حظر مؤشرات ترابط أخرى من الوصول إلى "الطريقة المتزامنة" أو "كتلة التعليمات البرمجية المتزامنة" من "الكائن".
المادة 2: عندما يصل مؤشر ترابط إلى "الطريقة المتزامنة" أو "كتلة التعليمات البرمجية المتزامنة" من "كائن معين" ، لا يزال بإمكان مؤشرات الترابط الأخرى الوصول إلى كتلة الكود غير المتزامن من "هذا الكائن".
المادة 3: عندما يصل مؤشر ترابط إلى "الطريقة المتزامنة" أو "كتلة رمز متزامنة" من "كائن معين" ، سيتم منع مؤشرات ترابط أخرى من الوصول إلى "طرق متزامنة أخرى" أو "كتلة رمز متزامنة" من "الكائن".
(1) المادة 1:
عندما يصل مؤشر ترابط إلى "الطريقة المتزامنة" أو "كتلة التعليمات البرمجية المتزامنة" من "كائن معين" ، سيتم حظر مؤشرات ترابط أخرى من الوصول إلى "الطريقة المتزامنة" أو "كتلة التعليمات البرمجية المتزامنة" من "الكائن". فيما يلي برنامج العرض التوضيحي المقابل لـ "كتلة الكود المتزامن".
class myrunable armements runnable {Override public void run () {synchronized (this) {try {for (int i = 0 ؛ i <5 ؛ i ++) {thread.sleep (100) ؛ // sleep 100ms system.out.println (thread.currentThRead (). getName () + "loop" + i) ؛ }} catch (InterruptedException ie) {}}}} الفئة العامة demo1_1 {public static void main (string [] args) {runnable demo = new myrunable () ؛ // إنشاء مؤشر ترابط جديد "Runnable Object" T1 = مؤشر ترابط جديد (DEMO ، "T1") ؛ // إنشاء "مؤشر ترابط T1" جديد ، يعتمد T1 على مؤشر ترابط الكائن القابل للتشغيل T2 = New Thread (Demo ، "T2") ؛ // إنشاء "موضوع T2" جديد ، يعتمد T2 على كائن Runnable T1.start () ؛ // ابدأ "Thread T1" t2.start () ؛ // ابدأ "موضوع T2"}} نتائج التشغيل:
T1 LOOP 0T1 LOOP 1T1 LOOP 2T1 LOOP 3T1 LOOP 4T2 LOOP 0T2 LOOP 1T2 LOOP 2T2 LOOP 3T2 LOOP 4
توضح النتيجة أن هناك "كتلة رمز (هذا) متزامن" في طريقة Run () ، و T1 و T2 هي مؤشرات ترابط تم إنشاؤها بناءً على الكائن "التجريبي". هذا يعني أنه يمكننا النظر في هذا في متزامن (هذا) كـ "كائن قابل للتشغيل التجريبي" ؛ لذلك ، تشترك المواضيع T1 و T2 "قفل متزامن للكائن التجريبي". لذلك ، عند تشغيل مؤشر ترابط واحد ، يجب أن ينتظر مؤشر ترابط آخر حتى يتم إطلاق "مؤشر الترابط الجري" على "قفل المزامنة التجريبية" قبل أن يتمكن من تشغيله.
إذا تأكدت ، فقد اكتشفت هذه المشكلة. ثم نقوم بتعديل الكود أعلاه ، ثم نديره لنرى كيف تكون النتيجة ، ومعرفة ما إذا كنت ستشعر بالارتباك. رمز المصدر المعدل كما يلي:
Class MyThread يمتد Thread {public mythread (اسم السلسلة) {super (name) ؛ } Override public void run () {Synchronized (this) {try {for (int i = 0 ؛ i <5 ؛ i ++) {thread.sleep (100) ؛ // sleep 100ms system.out.println (thread.currentThRead (). getName () + "loop" + i) ؛ }} catch (InterruptedException ie) {}}}} الفئة العامة demo1_2 {public static void main (string [] args) {thread t1 = new myThread ("t1") ؛ // إنشاء "موضوع T1" جديد T2 = جديد myThread ("T2") ؛ // إنشاء "Thread T2" t1.start () ؛ // ابدأ "Thread T1" t2.start () ؛ // ابدأ "موضوع T2"}} وصف الرمز: مقارنة Demo1_2 و Demo1_1 ، وجدنا أن فئة MyThread في Demo1_2 موروثة مباشرة من مؤشر الترابط ، و T1 و T2 كلاهما مؤشر ترابط طفل MyThread.
لحسن الحظ ، فإن طريقة "Run () لـ Demo1_2" تسمى أيضًا Synchronized (هذا) ، تمامًا مثل "طريقة Run () لـ Demo1_1" تسمى أيضًا Synchronized (هذا)!
إذن ، هل عملية تنفيذ Demo1_2 هي نفس عملية تنفيذ Demo1_1؟ نتائج التشغيل:
T1 LOOP 0T2 LOOP 0T1 LOOP 1T2 LOOP 1T1 LOOP 2T2 LOOP 2T1 LOOP 3T2 LOOP 3T1 LOOP 4T2 LOOP 4
وصف النتائج:
إذا كانت هذه النتيجة لا تفاجئك على الإطلاق ، فأعتقد أن لديك فهمًا أعمق للمزامنة وهذا. خلاف ذلك ، يرجى مواصلة قراءة التحليل هنا.
يشير هذا بالتواصل (هذا) إلى "كائن الفئة الحالي" ، أي الكائن الحالي المقابل للفئة التي يوجد فيها متزامن (هذا). الغرض منه هو الحصول على "قفل متزامن للكائن الحالي".
بالنسبة لـ Demo1_2 ، يمثل هذا في متزامن (هذا) كائن MyThread ، في حين أن T1 و T2 هما كائنان مختلفان MyThread. لذلك ، عندما ينفذ T1 و T2 متزامن (هذا) ، فإنهما يحصلون على أقفال المزامنة للكائنات المختلفة. بالنسبة لزوج Demo1_1 ، يمثل هذا بالشكل المزامن (هذا) الكائن القابل للتطبيق ؛ T1 و T2 يشاركان كائن myrunable. لذلك ، يحصل مؤشر ترابط واحد على قفل مزامنة الكائن ، مما سيؤدي إلى انتظار مؤشر ترابط آخر.
(2) المادة 2:
عندما يصل مؤشر ترابط إلى "الطريقة المتزامنة" أو "كتلة التعليمات البرمجية المتزامنة" من "كائن معين" ، لا يزال بإمكان مؤشرات الترابط الأخرى الوصول إلى كتلة التعليمات البرمجية غير المتزامنة من "هذا الكائن".
فيما يلي برنامج العرض التوضيحي المقابل لـ "كتلة الكود المتزامن".
Class Count {// طرق تحتوي على كتل المزامنة المتزامنة Synmethod () {Synchronized (this) {try {for (int i = 0 ؛ i <5 ؛ i ++) {thread.sleep (100) ؛ // sleep for 100ms system.out.println (thread.currentThread (). getName () + "synmethod loop" + i) ؛ }} catch (InterruptedException ie) {}}} // method غير متزامن الفراغ العام nonsynmethod () {try {for (int i = 0 ؛ i <5 ؛ i ++) {thread.sleep (100) ؛ System.out.println (thread.currentThRead (). getName () + "nonsynmethod loop" + i) ؛ }} catch (InterruptedException ie) {}}} demo2 {public static void main (string [] args) {final count count = new count () ؛ // إنشاء T1 جديد ، سوف يستدعي T1 طريقة synmethod () لـ "count Object" there t1 = new thread (new RunNable () {Override public void run () {count.synmethod () ؛}} ، "t1") ؛ // إنشاء T2 جديد ، سوف يستدعي T2 طريقة غير Nonsynmethod () لـ "Count Object" Twher t2 = new thread (new RunNable () {Override public void run () {count.nonsynmethod () ؛}} ، "t2") ؛ t1.start () ؛ // ابدأ t1 t2.start () ؛ // ابدأ T2}} نتائج التشغيل:
T1 synmethod loop 0t2 nonsynmethod loop 0t1 synmethod loop 1t2 nonsynmethod loop 1t1 synmethod loop 2t2 nonsynmethod loop 2t1 synmethod loop 3t2 nonsynmethod loop 3t1 synmethod loop 4t2 nonsynmethy
وصف النتائج:
يتم إنشاء خيوط طفل جديدة T1 و T2 في الخيط الرئيسي. سيسمي T1 طريقة synmethod () لكائن العد ، والذي يحتوي على كتل المزامنة ؛ سيقوم T2 بتسمية طريقة غير Nonsynmethod () لكائن COUNT ، والتي ليست طريقة المزامنة. عندما يتم تشغيل T1 ، على الرغم من أن متزامن (هذا) يتم استدعاؤه للحصول على "قفل مزامنة العد" ؛ لا يتسبب في حظر T2 لأن T2 لا يستخدم قفل مزامنة "العد".
(3) المادة 3:
عندما يصل مؤشر ترابط إلى "الطريقة المتزامنة" أو "كتلة التعليمات البرمجية المتزامنة" من "كائن معين" ، سيتم حظر مؤشرات الترابط الأخرى إلى "طرق متزامنة أخرى" أو "كتلة رمز متزامنة" من "الكائن" ".
سنقوم أيضًا بتعديل الجسم غير المتواصل () في المثال أعلاه مع متزامن (هذا). رمز المصدر المعدل كما يلي:
Class Count {// طرق تحتوي على كتل المزامنة المتزامنة Synmethod () {Synchronized (this) {try {for (int i = 0 ؛ i <5 ؛ i ++) {thread.sleep (100) ؛ // sleep for 100ms system.out.println (thread.currentThread (). getName () + "synmethod loop" + i) ؛ }} catch (InterruptedException ie) {}}} // الأساليب التي تحتوي على كتل المزامنة المتزامنة nonsynmethod () {synchronized (this) {try {for (int i = 0 ؛ i <5 ؛ i ++) {thread.sleep (100) ؛ System.out.println (thread.currentThRead (). getName () + "nonsynmethod loop" + i) ؛ }} catch (interruptedException ie) {}}}} demo3 {public static void main (string [] args) {final count count = new count () ؛ // Create T1 ، سوف يستدعي T1 طريقة synmethod () من مؤشر ترابط "كائن العد" T1 = جديد (جديد Runnable () {Override public void run () {count.syncmethod () ؛}} ، "T1") ؛ // إنشاء T2 جديد ، سيقوم T2 بتسمية طريقة nonsynmethod () لـ "Count Object" twher t2 = new thread (new RunNable () {Override public void run () {count.nonsynmethod () ؛}} ، "t2") ؛ t1.start () ؛ // ابدأ t1 t2.start () ؛ // ابدأ T2}} نتائج التشغيل:
T1 synmethod loop 0t1 synmethod loop 1t1 synmethod loop 2t1 synmethod loop 3t1 synmethod loop 4t2 nonsynmethod loop 0t2 nonsynmethod loop 1t2 nonsynmethod loop 2t2 nonsynmethod loop 3t2 nonsynm
وصف النتائج:
يتم إنشاء خيوط طفل جديدة T1 و T2 في الخيط الرئيسي. تم مزامنة كل من T1 و T2 Call (هذا) ، وهو كائن Count (العد) ، و T1 و T2. لذلك ، عند تشغيل T1 ، سيتم حظر T2 ، وسيتم تشغيل T1 لإطلاق "القفل المتزامن لكائن العد" قبل تشغيل T2.
3. الطريقة المتزامنة وكتلة الشفرة المتزامنة
تستخدم "الطريقة المتزامنة" طريقة التعديل المتزامن ، بينما تستخدم "كتلة الكود المتزامن" كتلة رمز التعديل المتزامن.
مثال طريقة متزامنة
proid void foo1 () {system.out.println ("طريقة متزامنة") ؛} كتلة رمز متزامنة الفراغ العام foo2 () {synchronized (this) {system.out.println ("methodized method") ؛ }} يشير هذا في كتلة الكود المتزامن إلى الكائن الحالي. يمكن استبدال هذا أيضًا بكائنات أخرى ، مثل هذا يتم استبداله بـ OBJ ، ثم يكتسب FOO2 () قفل مزامنة OBJ عند مزامنة (OBJ).
يمكن أن تتحكم كتل التعليمات البرمجية المتزامنة في مناطق الوصول المقيدة للصراع بدقة أكبر ، وأحيانًا تؤدي بشكل أكثر كفاءة. فيما يلي مثال لإظهار:
// DEMO4.JAVA Source Code Public Class Demo4 {public synchronized void synmethod () {for (int i = 0 ؛ i <1000000 ؛ i ++) ؛ } public void synblock () {synchronized (this) {for (int i = 0 ؛ i <1000000 ؛ i ++) ؛ }} public static void main (string [] args) {demo4 demo = new demo4 () ؛ بداية طويلة ، فرق ؛ start = system.currentTimeMillis () ؛ // احصل على الوقت الحالي (millis) demo.syncmethod () ؛ // استدعاء "طريقة متزامنة" diff = system.currentTimeMillis () - start ؛ // الحصول على "الفرق الزمني" system.out.println ("syncmethod ():"+ diff) ؛ start = system.currentTimeMillis () ؛ // احصل على الوقت الحالي (millis) demo.syncblock () ؛ // استدعاء "كتلة الطريقة المتزامنة" diff = system.currentTimeMillis () - start ؛ // الحصول على "الفرق الزمني" system.out.println ("syncblock ():"+ diff) ؛ }} (مرة واحدة) نتيجة التنفيذ:
synmethod (): 11synblock (): 3
4. قفل مثيل وقفل عالمي
مثيل قفل-محفور على كائن مثيل. إذا كان الفصل مفردة ، فإن القفل لديه أيضًا مفهوم قفل عالمي.
(1) تتوافق الكلمة الرئيسية المتزامنة مع قفل المثيل.
(2) القفل العالمي-يتم استهداف القفل في الفصل. بغض النظر عن عدد الكائنات على سبيل المثال ، تشترك مؤشرات الترابط في القفل.
يتوافق القفل العالمي مع متزامن ثابت (أو مغلق على فئة أو كائن تحميل الفصل في هذه الفئة).
هناك مثال حيوي للغاية على "قفل مثيل" و "قفل عالمي":
الفئة pulbic شيء {public synchronized void issynca () {} issyncb issyncb () {} لنفترض أن هناك شيئًا ما في حالتان X و Y. تحليل الأقفال التي اكتسبتها مجموعات التعبيرات الأربع التالية.
(1) x.issynca () و x.issyncb ()
(2) x.issynca () و y.issynca ()
(3) x.csynca () و y.csyncb ()
(4) x.issynca () وشيء. csynca ()
(1) لا يمكن الوصول إليها في وقت واحد.
لأن issynca () و issyncb () كلاهما أقفال المزامنة التي تصل إلى نفس الكائن (الكائن x)!
// locktest1.java فئة الكود المصدري شيء {public synchronized void issynca () {try {for (int i = 0 ؛ i <5 ؛ i ++) {thread.sleep (100) ؛ // sleep 100ms system.out.println (thread.currentThRead (). getName ()+": issynca") ؛ }} catch (interruptedException ie) {}} void void issyncb () {try {for (int i = 0 ؛ i <5 ؛ i ++) {thread.sleep (100) ؛ // sleep for 100ms system.out.println (thread.currentThRead (). getName ()+": issyncb") ؛ }} catch (InterruptedException ie) {}}} فئة عامة LockTest1 {something x = new something () ؛ شيء y = شيء جديد () ؛ // قارن (01) x.issynca () مع x.issyncb () private void test1 () {// إنشاء T11 جديد ، سوف يستدعي T11 x.issynca () Thread T11 = New Thread (New RunNable () {Override public void run () {x.issynca () ؛}}} ، "T11") ؛ // إنشاء T12 جديد ، T12 سوف يستدعي x.issyncb () مؤشر ترابط T12 = جديد (جديد RunNable () {Override public void run () {x.issyncb () ؛}} ، "T12") ؛ t11.start () ؛ // ابدأ T11 T12.Start () ؛ // ابدأ T12} الفراغ الثابت العام (سلسلة [] args) {locktest1 demo = new LockTest1 () ؛ demo.test1 () ؛ }} نتائج التشغيل:
T11: issyncat11: issyncat11: issyncat11: issyncat12: issyncbt12: issyncbt12: issyncbt12: issyncbt12: issyncbt12: issyncbt12: issyncbt12: issyncbt12: issyncb
(2) يمكن الوصول إليها في نفس الوقت
نظرًا لأنه لا يصل إلى قفل المزامنة لنفس الكائن ، فإن X.issynca () تصل إلى قفل المزامنة لـ x ، بينما يصل y.issynca () إلى قفل التزامن y.
// locktest2.java code source class شيء {public synchronized void issynca () {try {for (int i = 0 ؛ i <5 ؛ i ++) {thread.sleep (100) ؛ // sleep 100ms system.out.println (thread.currentThRead (). getName ()+": issynca") ؛ }} catch (interruptedException ie) {}} void void issyncb () {try {for (int i = 0 ؛ i <5 ؛ i ++) {thread.sleep (100) ؛ // sleep 100ms system.out.println (thread.currentThRead (). getName ()+": issyncb") ؛ }} catch (interruptedException ie) {}} public static void csynca () {try {for (int i = 0 ؛ i <5 ؛ i ++) {thread.sleep (100) ؛ // sleep 100ms system.out.println (thread.currentThRead (). getName ()+": csynca") ؛ }} catch (interruptedException ie) {}} public static void csyncb () {try {for (int i = 0 ؛ i <5 ؛ i ++) {thread.sleep (100) ؛ // sleep 100ms system.out.println (thread.currentThread (). getName ()+": csyncb") ؛ }} catch (InterruptedException ie) {}}} فئة عامة LockTest2 {something x = new something () ؛ شيء y = شيء جديد () ؛ // قارن (02) x.issynca () مع y.issynca () private void test2 () {// إنشاء T21 جديد ، سوف يستدعي T21 x.issynca () Thread T21 = new thread (new RunNable () // إنشاء T22 جديد ، سوف يستدعي T22 X.issyncb () Thread T22 = New Thread (New RunNable () {Override public void run () {y.issynca () ؛}} ، "T22") ؛ T21.start () ؛ // ابدأ T21 T22.start () ؛ // ابدأ T22} الفراغ الثابت العام (سلسلة [] args) {locktest2 demo = new LockTest2 () ؛ demo.test2 () ؛ }} نتائج التشغيل:
T21: issyncat22: issyncat21: issyncat22: issyncat21: issyncat22: issyncat21: issyncat22: issyncat21: issyncat22: issyncat21: issyncat22: issyncat21: issyncat2:
(3) لا يمكن الوصول إليها في وقت واحد
نظرًا لأن csynca () و csyncb () كلاهما نوعان ثابتان ، فإن x.csynca () يعادل شيئًا. sissynca () ، و y.csyncb () يعادل شيئًا.
// locktest3.java code class شيء {public synchronized void issynca () {try {for (int i = 0 ؛ i <5 ؛ i ++) {thread.sleep (100) ؛ // sleep 100ms system.out.println (thread.currentThRead (). getName ()+": issynca") ؛ }} catch (interruptedException ie) {}} void void issyncb () {try {for (int i = 0 ؛ i <5 ؛ i ++) {thread.sleep (100) ؛ // sleep 100ms system.out.println (thread.currentThRead (). getName ()+": issyncb") ؛ }} catch (interruptedException ie) {}} public static void csynca () {try {for (int i = 0 ؛ i <5 ؛ i ++) {thread.sleep (100) ؛ // sleep 100ms system.out.println (thread.currentThRead (). getName ()+": csynca") ؛ }} catch (interruptedException ie) {}} public static void csyncb () {try {for (int i = 0 ؛ i <5 ؛ i ++) {thread.sleep (100) ؛ // sleep 100ms system.out.println (thread.currentThread (). getName ()+": csyncb") ؛ }} catch (InterruptedException ie) {}}} فئة عامة LockTest3 {something x = new something () ؛ شيء y = شيء جديد () ؛ // قارن (03) X.CSYNCA () مع y.csyncb () private void test3 () {// إنشاء T31 ، t31 سوف يستدعي x.issynca () thread t31 = new thread (new RunNable () {override public run () {x.csynca () ؛ // إنشاء T32 جديد ، T32 سوف يستدعي x.issyncb () مؤشر ترابط T32 = جديد (جديد RunNable () {Override public void run () {y.csyncb () ؛}} ، "T32") ؛ T31.start () ؛ // ابدأ T31 T32.start () ؛ // ابدأ T32} الفراغ الثابت العام (سلسلة [] args) {locktest3 demo = new LockTest3 () ؛ demo.test3 () ؛ }} نتائج التشغيل:
T31: csyncat31: csyncat31: csyncat31: csyncat31: csyncat32: csyncbt32: csyncbt32: csyncbt32: csyncbt32: csyncbt32: csyncbt32: csyncbt32: csyncbt32: CSYNCB
(4) يمكن الوصول إليها في وقت واحد
لأن Issynca () طريقة مثيل ، يستخدم X.issynca () قفل الكائن X ؛ على الرغم من أن Csynca () هي طريقة ثابتة ، إلا أن شيئًا ما. csynca () يمكن أن يفهم أنه "قفل فئة" مستخدم. لذلك ، يمكن الوصول إليها في وقت واحد.
// locktest4.java code source class شيء {public synchronized void issynca () {try {for (int i = 0 ؛ i <5 ؛ i ++) {thread.sleep (100) ؛ // sleep 100ms system.out.println (thread.currentThRead (). getName ()+": issynca") ؛ }} catch (interruptedException ie) {}} void void issyncb () {try {for (int i = 0 ؛ i <5 ؛ i ++) {thread.sleep (100) ؛ // sleep 100ms system.out.println (thread.currentThRead (). getName ()+": issyncb") ؛ }} catch (interruptedException ie) {}} public static void csynca () {try {for (int i = 0 ؛ i <5 ؛ i ++) {thread.sleep (100) ؛ // sleep 100ms system.out.println (thread.currentThRead (). getName ()+": csynca") ؛ }} catch (interruptedException ie) {}} public static void csyncb () {try {for (int i = 0 ؛ i <5 ؛ i ++) {thread.sleep (100) ؛ // sleep for 100ms system.out.println (thread.currentThRead (). getName ()+": csyncb") ؛ }} catch (InterruptedException ie) {}}} فئة عامة LockTest4 {something x = new something () ؛ شيء y = شيء جديد () ؛ // قارن (04) X.issynca () مع شيء. // إنشاء T42 جديد ، سوف يستدعي T42 X.issyncb () Thread T42 = New Thread (New RunNable () {Override public void run () {something.csynca () ؛}} ، "T42") ؛ T41.start () ؛ // ابدأ T41 T42.Start () ؛ // ابدأ T42} الفراغ الثابت العام (سلسلة [] args) {locktest4 demo = new LockTest4 () ؛ demo.test4 () ؛ }} نتائج التشغيل:
T41: issyncat42: Csyncat41: issyncat42: csyncat41: issyncat42: csyncat41: issyncat42: csyncat41: issyncat42: csyncat41: issyncat42: csyncat41: