0. tentang sinkronisasi utas (1) Mengapa kita perlu menyinkronkan multithreading?
Sinkronisasi utas mengacu pada memungkinkan beberapa utas berjalan untuk bekerja sama dengan baik untuk memungkinkan beberapa utas untuk menempati dan melepaskan sumber daya yang wajar sesuai kebutuhan. Kami menggunakan blok kode sinkronisasi dan metode sinkronisasi di Java untuk mencapai tujuan ini. Misalnya, selesaikan masalah eksekusi pesanan multi-threaded yang tidak ditanam:
kelas publik twothreadtest {public static void main (string [] args) {thread th1 = new mythread1 (); Thread tH2 = myThread2 baru (); th1.start (); th2.start (); }} kelas myThread2 memperluas thread {@Override public void run () {for (int i = 0; i <10; i ++) sistem. out.println ("Thread 1 Counter:"+i); }} kelas myThread1 memperluas thread {@Override public void run () {for (int i = 0; i <10; i ++) sistem. out.println ("Thread 1 Counter:"+i); }} kelas myThread1 memperluas thread {@Override public void run () {for (int i = 0; i <10; i ++) sistem. out.println ("Thread 2 Counter:"+i); }}Hasil eksekusi multi-utas dalam keadaan ini adalah untuk memasukkan eksekusi secara acak sesuka hati, yang sepenuhnya tergantung pada penjadwalan utas JVM. Dalam banyak kasus di mana eksekusi tertib diperlukan, keadaan eksekusi acak ini jelas tidak cocok.
Public Class ThreadTest {public static void main (string [] args) {mythread thread = new mythread (); Thread tH1 = utas baru (utas); Thread tH2 = utas baru (utas); th1.start (); th2.start (); }} kelas MyThread mengimplementasikan runnable {@Override public disinkronkan void run () {for (int i = 0; i <10; i ++) sistem. out.println (thread. currentThread (). getName ()+"counter:"+i); }}Setelah menggunakan metode sinkronisasi, kita dapat mengontrol utas untuk secara eksklusif menempati objek tubuh eksekusi. Dengan cara ini, selama proses eksekusi, utas dapat menjalankan tugas pada badan eksekusi pada satu waktu dan keluar dari status kunci. JVM kemudian mengirim utas lain untuk menjalankan tugas di badan eksekusi pada satu waktu.
(2) Paradigma untuk pembuatan dan menjalankan utas:
Di masa lalu, kami juga memiliki paradigma pemrograman sendiri untuk pembuatan dan berlari utas. Secara umum, kami mendefinisikan kelas eksekusi untuk menulis ulang metode run (), tetapi metode ini menempatkan badan eksekusi dan tugas yang dieksekusi bersama -sama, yang tidak kondusif untuk memisahkan dari perspektif rekayasa perangkat lunak. Eksekusi utas berarti bahwa utas mengeksekusi tugas objek melalui objek eksekusi. Dari perspektif ini, memisahkan prescriber tugas dari kelas eksekusi dapat membuat berbagai peran pemrograman multi-threaded jelas dan dengan demikian mendapatkan decoupling yang baik. Berikut ini adalah paradigma pemrograman untuk pembuatan dan eksekusi utas:
kelas publik formalThreadclass {public static void main (string [] args) {thread thread = thread baru (new myrunnable ()); thread.start (); }} kelas myRunnable implement runnable {mytask mytask = myTask baru (); @Override public void run () {mytask.dotaSk (); }} kelas myTask {public void dotask () {System. out.println ("Ini penugasan nyata"); }}
1. Prinsip yang disinkronkan
Di Java, setiap objek memiliki dan hanya memiliki satu kunci sinkronisasi. Ini juga berarti bahwa kunci sinkronisasi ada pada objek.
Ketika kami memanggil metode sinkronisasi suatu objek, kami memperoleh kunci sinkronisasi objek. Misalnya, disinkronkan (OBJ) memperoleh kunci sinkronisasi "objek OBJ".
Akses ke kunci sinkronisasi oleh utas yang berbeda saling eksklusif. Dengan kata lain, pada titik waktu tertentu, kunci sinkronisasi objek hanya dapat diperoleh dengan satu utas! Melalui kunci sinkronisasi, kita dapat mencapai akses yang saling eksklusif ke "objek/metode" di banyak utas. Misalnya, sekarang ada dua utas A dan Thread B, yang keduanya mengakses "kunci sinkron objek OBJ". Misalkan pada titik tertentu, encer A memperoleh "kunci sinkronisasi OBJ" dan melakukan beberapa operasi; Pada saat ini, Thread B juga mencoba untuk mendapatkan "kunci sinkronisasi OBJ" - Thread B akan gagal untuk memperoleh, ia harus menunggu sampai utas A melepaskan "kunci sinkronisasi OBJ" dan hanya dapat dijalankan.
2. Aturan Dasar Sinkronisasi
Kami merangkum aturan dasar yang disinkronkan ke dalam 3 berikut dan menggambarkannya melalui contoh.
Pasal 1: Ketika utas mengakses "metode yang disinkronkan" atau "blok kode yang disinkronkan" dari "objek tertentu", utas lain akan diblokir dari akses ke "metode sinkronisasi" atau "blok kode yang disinkronkan" dari "objek".
Pasal 2: Ketika utas mengakses "metode yang disinkronkan" atau "blok kode yang disinkronkan" dari "objek tertentu", utas lain masih dapat mengakses blok kode yang disinkronkan dari "objek ini".
Pasal 3: Ketika utas mengakses "metode yang disinkronkan" atau "blok kode yang disinkronkan" dari "objek tertentu", utas lain akan diblokir dari mengakses "metode sinkronisasi" lainnya atau "blok kode yang disinkronkan" dari "objek".
(1) Pasal 1:
Ketika utas mengakses "metode sinkronisasi" atau "blok kode yang disinkronkan" dari "objek tertentu", utas lain akan diblokir dari akses ke "metode yang disinkronkan" atau "blok kode yang disinkronkan" dari "objek". Di bawah ini adalah program demonstrasi yang sesuai dengan "blok kode yang disinkronkan".
kelas MyRunable mengimplementasikan runnable {@Override public void run () {disinkronkan (this) {try {for (int i = 0; i <5; i ++) {thread.sleep (100); // tidur 100ms System.out.println (thread.currentThread (). GetName () + "loop" + i); }} catch (InterruptedException IE) {}}}} kelas publik demo1_1 {public static void main (string [] args) {runnable demo = new myRunable (); // Buat Thread "Runnable Object" baru T1 = utas baru (demo, "T1"); // Buat "Thread T1" baru, T1 didasarkan pada utas objek Runnable T2 = utas baru (demo, "T2"); // Buat "Thread T2" baru, T2 didasarkan pada objek runnable t1.start (); // Mulai "Thread T1" t2.start (); // Mulai "Thread T2"}} Hasil Menjalankan:
Loop T1 0T1 Loop 1T1 Loop 2T1 Loop 3T1 Loop 4t2 Loop 0T2 Loop 1T2 Loop 2t2 Loop 3T2 Loop 4
Hasilnya menunjukkan bahwa ada "blok kode yang disinkronkan (ini)" dalam metode run (), dan T1 dan T2 adalah utas yang dibuat berdasarkan objek "demo" yang dapat dijalankan. Ini berarti bahwa kita dapat menganggap ini dalam sinkronisasi (ini) sebagai "objek demo runnable"; Oleh karena itu, utas T1 dan T2 berbagi "kunci sinkron dari objek demo". Oleh karena itu, ketika satu utas berjalan, utas lain harus menunggu "utas berjalan" untuk melepaskan "kunci sinkronisasi demo" sebelum dapat berjalan.
Jika Anda mengonfirmasi, Anda menemukan masalah ini. Kemudian kami memodifikasi kode di atas, dan kemudian menjalankannya untuk melihat bagaimana hasilnya, dan melihat apakah Anda akan bingung. Kode sumber yang dimodifikasi adalah sebagai berikut:
kelas mythread memperluas utas {public mythread (nama string) {super (name); } @Override public void run () {disinkronkan (ini) {coba {for (int i = 0; i <5; i ++) {thread.sleep (100); // tidur 100ms System.out.println (thread.currentThread (). GetName () + "loop" + i); }} catch (InterruptedException IE) {}}}} kelas publik demo1_2 {public static void main (string [] args) {thread t1 = mythread baru ("t1"); // Buat "Thread T1" Thread T2 = MyThread baru ("T2"); // Buat "Thread T2" T1.start () baru; // Mulai "Thread T1" t2.start (); // Mulai "Thread T2"}} Deskripsi Kode: Membandingkan Demo1_2 dan Demo1_1, kami menemukan bahwa kelas MyThread di Demo1_2 secara langsung diwariskan dari utas, dan T1 dan T2 keduanya adalah utas anak Mythread.
Untungnya, metode "run () dari demo1_2" juga disebut disinkronkan (ini), seperti halnya metode "run () dari demo1_1" juga disebut disinkronkan (ini)!
Jadi, apakah proses eksekusi demo1_2 sama dengan demo1_1? Hasil Menjalankan:
Loop T1 0T2 Loop 0T1 Loop 1T2 Loop 1T1 Loop 2t2 Loop 2T1 Loop 3T2 Loop 3T1 Loop 4t2 Loop 4
Deskripsi Hasil:
Jika hasil ini tidak mengejutkan Anda sama sekali, maka saya percaya bahwa Anda memiliki pemahaman yang lebih dalam tentang sinkronisasi dan ini. Jika tidak, silakan lanjutkan membaca analisis di sini.
Ini dalam sinkronisasi (ini) mengacu pada "objek kelas saat ini", yaitu objek saat ini yang sesuai dengan kelas di mana disinkronkan (ini) berada. Tujuannya adalah untuk mendapatkan "kunci sinkron dari objek saat ini".
Untuk Demo1_2, ini disinkronkan (ini) mewakili objek Mythread, sedangkan T1 dan T2 adalah dua objek Mythread yang berbeda. Oleh karena itu, ketika T1 dan T2 mengeksekusi sinkronisasi (ini), mereka memperoleh kunci sinkronisasi dari berbagai objek. Untuk pasangan Demo1_1, ini disinkronkan (ini) mewakili objek yang dapat diringkas; T1 dan T2 Bagikan objek yang dapat digerakkan. Oleh karena itu, satu utas memperoleh kunci sinkronisasi objek, yang akan menyebabkan utas lain menunggu.
(2) Pasal 2:
Ketika utas mengakses "metode yang disinkronkan" atau "blok kode yang disinkronkan" dari "objek tertentu", utas lain masih dapat mengakses blok kode yang disinkronkan dari "objek ini".
Di bawah ini adalah program demonstrasi yang sesuai dengan "blok kode yang disinkronkan".
Class Count {// Metode yang mengandung sinkronisasi sinkronisasi blok public void synmethod () {disinkronkan (this) {try {for (int i = 0; i <5; i ++) {thread.sleep (100); // tidur untuk 100ms System.out.println (thread.currentThread (). GetName () + "Synmethod loop" + i); }} catch (InterruptedException IE) {}}} // Metode asinkron public void nonsynmethod () {coba {for (int i = 0; i <5; i ++) {thread.sleep (100); System.out.println (thread.currentThread (). GetName () + "loop nonsynmethod" + i); }} catch (InterruptedException IE) {}}} public class demo2 {public static void main (string [] args) {final count count = new count (); // Buat T1 baru, T1 akan memanggil metode synmethod () dari "Count Object" Thread T1 = utas baru (runnable baru () {@Override public void run () {count.synmethod ();}}, "t1"); // Buat metode T2 baru, T2 akan memanggil metode nonsynmethod () dari "objek hitungan" utas T2 = utas baru (runnable baru () {@Override public void run () {count.nonsynmethod ();}}, "t2"); t1.start (); // Mulai t1 t2.start (); // Mulai T2}} Hasil Menjalankan:
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 nonSynMethod loop 4
Deskripsi Hasil:
Dua utas anak baru T1 dan T2 dibuat di utas utama. T1 akan memanggil metode synmethod () dari objek penghitungan, yang berisi blok sinkronisasi; T2 akan memanggil metode nonsynmethod () dari objek Count, yang bukan metode sinkronisasi. Ketika T1 berjalan, meskipun disinkronkan (ini) dipanggil untuk mendapatkan "kunci sinkronisasi jumlah"; Itu tidak menyebabkan T2 memblokir karena T2 tidak menggunakan kunci sinkronisasi "hitung".
(3) Pasal 3:
Ketika utas mengakses "metode sinkronisasi" atau "blok kode yang disinkronkan" dari "objek tertentu", akses utas lain ke "metode sinkronisasi" lainnya atau "blok kode yang disinkronkan" dari "objek" akan diblokir.
Kami juga akan memodifikasi badan metode nonsynmethod () dalam contoh di atas dengan disinkronkan (ini). Kode sumber yang dimodifikasi adalah sebagai berikut:
Class Count {// Metode yang mengandung sinkronisasi sinkronisasi blok public void synmethod () {disinkronkan (this) {try {for (int i = 0; i <5; i ++) {thread.sleep (100); // tidur untuk 100ms System.out.println (thread.currentThread (). GetName () + "Synmethod loop" + i); }} catch (InterruptedException IE) {}}} // Metode yang mengandung sinkronisasi sinkronisasi blok public void nonsynmethod () {disinkronkan (ini) {coba {untuk (int i = 0; i <5; i ++) {thread.sleep (100); System.out.println (thread.currentThread (). GetName () + "loop nonsynmethod" + i); }} catch (InterruptedException IE) {}}}} kelas publik Demo3 {public static void main (string [] args) {final count count = new count (); // Buat t1, t1 akan memanggil metode synmethod () dari "count objek" utas T1 = utas baru (runnable baru () {@Override public void run () {count.syncmethod ();}}, "t1"); // Buat T2 baru, T2 akan memanggil metode nonsynmethod () dari "count objek" utas T2 = utas baru (runnable baru () {@Override public void run () {count.nonsynmethod ();}, "t2"); t1.start (); // Mulai t1 t2.start (); // Mulai T2}} Hasil Menjalankan:
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 nonSynMethod loop 4
Deskripsi Hasil:
Dua utas anak baru T1 dan T2 dibuat di utas utama. Baik panggilan T1 dan T2 disinkronkan (ini), yang merupakan objek penghitungan (hitungan), dan jumlah saham T1 dan T2. Oleh karena itu, ketika T1 berjalan, T2 akan diblokir, dan T1 akan dijalankan untuk melepaskan "kunci sinkron objek penghitungan" sebelum T2 dapat berjalan.
3. Metode yang disinkronkan dan blok kode yang disinkronkan
"Metode Sinkronisasi" menggunakan metode modifikasi yang disinkronkan, sedangkan "blok kode yang disinkronkan" menggunakan blok kode modifikasi yang disinkronkan.
Contoh metode yang disinkronkan
public disinkronkan void foo1 () {System.out.println ("Metode Sinkronisasi");} Kode Sinkronisasi Blok Public Void FOO2 () {disinkronkan (this) {System.out.println ("Metode Sinkronisasi"); }} Ini di blok kode yang disinkronkan mengacu pada objek saat ini. Ini juga dapat diganti dengan objek lain, seperti ini diganti dengan OBJ, kemudian FOO2 () memperoleh kunci sinkronisasi OBJ ketika disinkronkan (OBJ).
Blok kode yang disinkronkan dapat mengontrol area akses yang dibatasi konflik dengan lebih akurat, dan kadang-kadang berkinerja lebih efisien. Berikut adalah contoh untuk menunjukkan:
// Demo4.Java's Sumber Code Public Class Demo4 {public disinkronkan void synmethod () {for (int i = 0; i <1000000; i ++); } public void synblock () {disinkronkan (ini) {for (int i = 0; i <1000000; i ++); }} public static void main (string [] args) {demo4 demo = new demo4 (); Mulai lama, diff; start = system.currentTimeMillis (); // Dapatkan Demo.syncmethod (Millis) saat ini; // panggil "metode sinkronisasi" diff = system.currentTimeMillis () - start; // Dapatkan "Perbedaan Waktu" System.out.println ("SyncMethod ():"+ Diff); start = system.currentTimeMillis (); // Dapatkan waktu (Millis) Demo.syncblock () saat ini; // panggil "blok metode sinkron" diff = system.currentTimeMillis () - start; // Dapatkan "Perbedaan Waktu" System.out.println ("SyncBlock ():"+ Diff); }} (Satu kali) Hasil Eksekusi:
synmethod (): 11synblock (): 3
4. Kunci instan dan kunci global
Kunci instan-terkunci pada objek instan. Jika kelas adalah singleton, maka kunci juga memiliki konsep kunci global.
(1) Kata kunci yang disinkronkan sesuai dengan kunci instance.
(2) Global Lock-Kunci ditargetkan pada kelas. Tidak peduli berapa banyak objek contohnya, utas berbagi kunci.
Kunci global sesuai dengan sinkronisasi statis (atau terkunci pada kelas atau objek ClassLoader dari kelas ini).
Ada contoh yang sangat jelas dari "kunci instance" dan "Global Lock":
Kelas PULBIC Sesuatu {public disinkronkan void issynca () {} public disinkronkan void issyncb () {} public static static void csynca () {} public static void csyncB () {}} public static static void csyncb () {}} public static static void csyncb () Misalkan, ada sesuatu yang memiliki dua contoh x dan y. Analisis kunci yang diperoleh dengan empat set ekspresi berikut.
(1) x.issynca () dan x.issyncb ()
(2) x.issynca () dan y.issynca ()
(3) x.csynca () dan y.csyncb ()
(4) x.issynca () dan sesuatu.csynca ()
(1) tidak dapat diakses secara bersamaan.
Karena issynca () dan issyncb () keduanya kunci sinkronisasi yang mengakses objek yang sama (objek X)!
// LockTest1.java's Source Code Class Sesuatu {public disinkronkan void issynca () {coba {for (int i = 0; i <5; i ++) {thread.sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName ()+": issynca"); }} catch (InterruptedException IE) {}} public disinkronkan void issyncb () {coba {for (int i = 0; i <5; i ++) {thread.sleep (100); // tidur untuk 100ms System.out.println (thread.currentThread (). GetName ()+": issyncb"); }} catch (InterruptedException IE) {}}} kelas publik lockTest1 {sesuatu x = new sesuatu (); Sesuatu y = new sesuatu (); // bandingkan (01) x.issynca () dengan x.issyncb () private void test1 () {// Buat t11 baru, t11 akan menghubungi x.issynca () utas t11 = utas baru (runnable baru () {@override public void run () {x.issynca ();}}, "t11"); // Buat T12 baru, T12 akan menghubungi x.issyncb () utas t12 = utas baru (runnable baru () {@Override public void run () {x.issyncb ();}}, "t12"); t11.start (); // Mulai t11 t12.start (); // Mulai t12} public static void main (string [] args) {lockTest1 demo = new LockTest1 (); demo.test1 (); }} Hasil Menjalankan:
T11: ISSYNCAT11: ISSYNCAT11: ISSYNCAT11: ISSYNCAT12: ISSYNCBT12: ISSYNCBT12: ISSYNCBT12: ISSYNCBT12: ISSYNCBT12: ISSYNCBT12: ISSYNCBT12: ISSYNCBT12: ISSNCBB:
(2) dapat diakses secara bersamaan
Karena tidak mengakses kunci sinkronisasi dari objek yang sama, x.issynca () mengakses kunci sinkronisasi X, sementara y.issynca () mengakses kunci sinkronisasi Y.
// LockTest2.Java's Source Code Class Sesuatu {public disinkronkan void issynca () {coba {for (int i = 0; i <5; i ++) {thread.sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName ()+": issynca"); }} catch (InterruptedException IE) {}} public disinkronkan void issyncb () {coba {for (int i = 0; i <5; i ++) {thread.sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName ()+": issyncb"); }} catch (InterruptedException IE) {}} public static static void csynca () {coba {for (int i = 0; i <5; i ++) {thread.sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName ()+": csynca"); }} catch (InterruptedException IE) {}} public static static void csyncb () {coba {for (int i = 0; i <5; i ++) {thread.sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName ()+": csyncb"); }} catch (InterruptedException IE) {}}} kelas publik lockTest2 {sesuatu x = new sesuatu (); Sesuatu y = new sesuatu (); // Bandingkan (02) x.issynca () dengan y.issynca () private void test2 () {// Buat t21 baru, t21 akan menghubungi x.issynca () thread t21 = utas baru (runnable baru () {@Override public run () {x.issynca ();}, "@Override public run () {x.issynca ();}," T21 () {x.issynca (); " // Buat T22 baru, T22 akan menghubungi x.issyncb () utas t22 = utas baru (runnable baru () {@Override public void run () {y.issynca ();}}, "t22"); t21.start (); // Mulai T21 T22.Start (); // Mulai t22} public static void main (string [] args) {lockTest2 demo = new LockTest2 (); demo.test2 (); }} Hasil Menjalankan:
T21: Issyncat22: Issyncat21: Issyncat22: Issyncat21: Issyncat22: Issyncat21: Issyncat22: Issyncat21: Issyncat22: Issyncat21: Issyncat22: Issyncat21: Issyncat22:
(3) tidak dapat diakses secara bersamaan
Karena csynca () dan csyncb () keduanya tipe statis, x.csynca () setara dengan sesuatu.
// LockTest3.java's Source Code Class Sesuatu {public disinkronkan void issynca () {coba {for (int i = 0; i <5; i ++) {thread.sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName ()+": issynca"); }} catch (InterruptedException IE) {}} public disinkronkan void issyncb () {coba {for (int i = 0; i <5; i ++) {thread.sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName ()+": issyncb"); }} catch (InterruptedException IE) {}} public static static void csynca () {coba {for (int i = 0; i <5; i ++) {thread.sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName ()+": csynca"); }} catch (InterruptedException IE) {}} public static static void csyncb () {coba {for (int i = 0; i <5; i ++) {thread.sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName ()+": csyncb"); }} catch (InterruptedException IE) {}}} Kelas publik LockTest3 {Something x = new Something (); Sesuatu y = new sesuatu (); // Bandingkan (03) x.csynca () dengan y.csyncb () private void test3 () {// Buat t31 baru, t31 akan menghubungi x.issynca () utas T31 = utas baru (runnable baru () {@override void run () {x.csynca ();}}} {@override () {) {) {x.csynca (); // Buat T32 baru, T32 akan menghubungi x.issyncb () utas T32 = utas baru (runnable baru () {@Override public void run () {y.csyncb ();}}, "t32"); t31.start (); // Mulai T31 T32.Start (); // Mulai T32} public static void main (string [] args) {lockTest3 demo = new LockTest3 (); demo.test3 (); }} Hasil Menjalankan:
t31: cSyncAt31: cSyncAt31: cSyncAt31: cSyncAt31: cSyncAt32: cSyncBt32: cSyncBt32: cSyncBt32: cSyncBt32: cSyncBt32: cSyncBt32: cSyncBt32: cSyncBt32: cSyncBt32: csyncb
(4) dapat diakses secara bersamaan
Karena issynca () adalah metode instan, x.issynca () menggunakan kunci objek X; Sementara csynca () adalah metode statis, sesuatu.csynca () dapat memahami bahwa itu adalah "kunci kelas" yang digunakan. Karena itu, mereka dapat diakses secara bersamaan.
// lockTest4.java's Source Code Class Sesuatu {public disinkronkan void issynca () {coba {for (int i = 0; i <5; i ++) {thread.sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName ()+": issynca"); }} catch (InterruptedException IE) {}} public disinkronkan void issyncb () {coba {for (int i = 0; i <5; i ++) {thread.sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName ()+": issyncb"); }} catch (InterruptedException IE) {}} public static static void csynca () {coba {for (int i = 0; i <5; i ++) {thread.sleep (100); // Sleep 100ms System.out.println (thread.currentThread (). GetName ()+": csynca"); }} catch (InterruptedException IE) {}} public static static void csyncb () {coba {for (int i = 0; i <5; i ++) {thread.sleep (100); // tidur untuk 100ms System.out.println (thread.currentThread (). GetName ()+": csyncb"); }} catch (InterruptedException IE) {}}} kelas publik lockTest4 {sesuatu x = new sesuatu (); Sesuatu y = new sesuatu (); // bandingkan (04) x.issynca () dengan sesuatu.csynca () private void test4 () {// Buat t41 baru, t41 akan menghubungi x.issynca () thread t41 = utas baru (runnable baru () {@override void run () {x.issynca ();}} {@override t4 () {x.issynca (); // Buat T42 baru, T42 akan menghubungi x.issyncb () utas T42 = utas baru (runnable baru () {@Override public void run () {Something.csynca ();}}, "t42"); t41.start (); // Mulai T41 T42.Start (); // Mulai t42} public static void main (string [] args) {lockTest4 demo = new LockTest4 (); demo.test4 (); }} Hasil Menjalankan:
T41: ISSYNCAT42: CSYNCAT41: ISSYNCAT42: CSYNCAT41: ISSYNCAT42: CSYNCAT41: ISSYNCAT42: CSYNCAT41: ISSYNCAT42: CSYNCAT41: ISSYNCAT42: CSYNCAT41: CSYNCAT41: ISSYNCAT42: CSYNCAT41: CSYNCAT41: ISSYNCAT42: CSYNCAT41: CSYNCAT41: CSYNCAT42: CSYNCAT41: CSYNCAT42: CSYNCAT42: CSYNCAT41: CSYNCAT41: CSYNCA