Perkenalan
Jadi, kita tahu bahwa Java memiliki utas. Anda dapat membacanya di ulasan berjudul Lebih baik bersama: Java dan kelas Thread. Bagian I — Utas eksekusi . Utas diperlukan untuk melakukan pekerjaan secara paralel. Hal ini membuat sangat mungkin bahwa utas entah bagaimana akan berinteraksi satu sama lain. Mari kita lihat bagaimana ini terjadi dan alat dasar apa yang kita miliki.
Menghasilkan
Thread.yield() membingungkan dan jarang digunakan. Ini dijelaskan dengan berbagai cara di Internet. Termasuk beberapa orang menulis bahwa ada beberapa antrian utas, di mana utas akan turun berdasarkan prioritas utas. Orang lain menulis bahwa utas akan mengubah statusnya dari "Berjalan" menjadi "Dapat dijalankan" (meskipun tidak ada perbedaan antara status ini, yaitu Java tidak membedakannya). Kenyataannya adalah bahwa itu semua kurang terkenal namun lebih sederhana dalam arti tertentu.
yield()
dokumentasi metode. Jika Anda membacanya, jelas bahwayield()
metode sebenarnya hanya memberikan beberapa rekomendasi kepada penjadwal utas Java agar utas ini dapat diberikan waktu eksekusi yang lebih sedikit. Tetapi apa yang sebenarnya terjadi, yaitu apakah penjadwal bertindak berdasarkan rekomendasi dan apa yang dilakukannya secara umum, bergantung pada implementasi JVM dan sistem operasi. Dan itu mungkin tergantung pada beberapa faktor lain juga. Semua kebingungan kemungkinan besar disebabkan oleh fakta bahwa multithreading telah dipikirkan kembali seiring dengan perkembangan bahasa Java. Baca selengkapnya di ikhtisar di sini: Pengantar Singkat tentang Java Thread.yield() .
Tidur
Sebuah utas dapat tertidur selama eksekusi. Ini adalah jenis interaksi termudah dengan utas lainnya. Sistem operasi yang menjalankan mesin virtual Java yang menjalankan kode Java kami memiliki penjadwal utasnya sendiri . Ini memutuskan utas mana yang akan dimulai dan kapan. Seorang programmer tidak dapat berinteraksi dengan penjadwal ini langsung dari kode Java, hanya melalui JVM. Dia dapat meminta penjadwal untuk menjeda utas untuk sementara waktu, yaitu untuk menidurkannya. Anda dapat membaca lebih lanjut di artikel ini: Thread.sleep() dan How Multithreading works . Anda juga dapat melihat cara kerja utas di sistem operasi Windows: Internals of Windows Thread . Dan sekarang mari kita lihat dengan mata kepala sendiri. Simpan kode berikut dalam file bernamaHelloWorldApp.java
:
class HelloWorldApp {
public static void main(String []args) {
Runnable task = () -> {
try {
int secToWait = 1000 * 60;
Thread.currentThread().sleep(secToWait);
System.out.println("Woke up");
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Thread thread = new Thread(task);
thread.start();
}
}
Seperti yang Anda lihat, kami memiliki beberapa tugas yang menunggu selama 60 detik, setelah itu program berakhir. Kami mengkompilasi menggunakan perintah " javac HelloWorldApp.java
" dan kemudian menjalankan program menggunakan " java HelloWorldApp
". Yang terbaik adalah memulai program di jendela terpisah. Misalnya di Windows, seperti ini: start java HelloWorldApp
. Kami menggunakan perintah jps untuk mendapatkan PID (ID proses), dan kami membuka daftar utas dengan " jvisualvm --openpid pid
: 
try {
TimeUnit.SECONDS.sleep(60);
System.out.println("Woke up");
} catch (InterruptedException e) {
e.printStackTrace();
}
Apakah Anda memperhatikan bahwa kami menangani InterruptedException
di mana-mana? Mari kita pahami alasannya.
Utas.interrupt()
Masalahnya adalah saat utas sedang menunggu/tidur, seseorang mungkin ingin menyela. Dalam hal ini, kami menangani fileInterruptedException
. Mekanisme ini dibuat setelah Thread.stop()
metode tersebut dinyatakan Deprecated, yaitu kedaluwarsa dan tidak diinginkan. Alasannya adalah ketika stop()
metode dipanggil, utasnya hanya "dibunuh", yang sangat tidak dapat diprediksi. Kami tidak dapat mengetahui kapan utas akan dihentikan, dan kami tidak dapat menjamin konsistensi data. Bayangkan Anda sedang menulis data ke file saat utas dimatikan. Daripada mematikan utas, pembuat Java memutuskan bahwa akan lebih logis untuk mengatakan bahwa utas harus diinterupsi. Bagaimana menanggapi informasi ini adalah masalah yang diputuskan oleh utas itu sendiri. Untuk detail selengkapnya, baca Mengapa Thread.stop tidak digunakan lagi?di situs web Oracle. Mari kita lihat sebuah contoh:
public static void main(String []args) {
Runnable task = () -> {
try {
TimeUnit.SECONDS.sleep(60);
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
};
Thread thread = new Thread(task);
thread.start();
thread.interrupt();
}
Dalam contoh ini, kami tidak akan menunggu 60 detik. Sebagai gantinya, kami akan segera menampilkan "Terganggu". Ini karena kami memanggil interrupt()
metode di utas. Metode ini menyetel bendera internal yang disebut "status interupsi". Artinya, setiap utas memiliki bendera internal yang tidak dapat diakses secara langsung. Tapi kami memiliki metode asli untuk berinteraksi dengan bendera ini. Tapi itu bukan satu-satunya cara. Utas mungkin sedang berjalan, tidak menunggu sesuatu, hanya melakukan tindakan. Tetapi mungkin mengantisipasi bahwa orang lain ingin mengakhiri pekerjaannya pada waktu tertentu. Misalnya:
public static void main(String []args) {
Runnable task = () -> {
while(!Thread.currentThread().isInterrupted()) {
// Do some work
}
System.out.println("Finished");
};
Thread thread = new Thread(task);
thread.start();
thread.interrupt();
}
Pada contoh di atas, while
loop akan dijalankan hingga utas diinterupsi secara eksternal. Sedangkan untuk isInterrupted
flag, penting untuk diketahui bahwa jika kita menangkap sebuah InterruptedException
, flag isInterrupted akan direset, dan kemudian isInterrupted()
mengembalikan false. Kelas Thread juga memiliki metode Thread.interrupted() statis yang hanya berlaku untuk thread saat ini, tetapi metode ini menyetel ulang flag ke false! Baca lebih lanjut dalam bab ini berjudul Thread Interruption .
Gabung (Tunggu utas lainnya selesai)
Jenis penantian yang paling sederhana adalah menunggu utas lainnya selesai.
public static void main(String []args) throws InterruptedException {
Runnable task = () -> {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
};
Thread thread = new Thread(task);
thread.start();
thread.join();
System.out.println("Finished");
}
Dalam contoh ini, utas baru akan tidur 5 detik. Pada saat yang sama, utas utama akan menunggu hingga utas tidur bangun dan menyelesaikan pekerjaannya. Jika Anda melihat status utas di JVisualVM, maka akan terlihat seperti ini: 
join
cukup sederhana, karena ini hanyalah metode dengan kode Java yang dijalankan wait()
selama utas yang dipanggil masih hidup. Segera setelah utas mati (ketika selesai dengan pekerjaannya), penantian terputus. Dan itu semua keajaiban dari join()
metode ini. Jadi, mari beralih ke hal yang paling menarik.
Memantau
Multithreading mencakup konsep monitor. Kata monitor datang ke bahasa Inggris melalui bahasa Latin abad ke-16 dan berarti "instrumen atau perangkat yang digunakan untuk mengamati, memeriksa, atau menyimpan catatan berkelanjutan dari suatu proses". Dalam konteks artikel ini, kami akan mencoba membahas dasar-dasarnya. Bagi siapa pun yang menginginkan detailnya, silakan selami materi yang ditautkan. Kami memulai perjalanan kami dengan Spesifikasi Bahasa Jawa (JLS): 17.1. Sinkronisasi . Dikatakan sebagai berikut:
lock()
atau melepaskannya dengan unlock()
. Selanjutnya, kita akan menemukan tutorialnya di website Oracle: Intrinsic Locks and Synchronization. Tutorial ini mengatakan bahwa sinkronisasi Java dibangun di sekitar entitas internal yang disebut kunci intrinsik atau monitor lock . Kunci ini sering disebut " monitor ". Kami juga melihat lagi bahwa setiap objek di Java memiliki kunci intrinsik yang terkait dengannya. Anda dapat membaca Java - Intrinsic Locks and Synchronization . Selanjutnya, penting untuk memahami bagaimana sebuah objek di Java dapat diasosiasikan dengan monitor. Di Java, setiap objek memiliki header yang menyimpan metadata internal yang tidak tersedia untuk pemrogram dari kode, tetapi mesin virtual perlu bekerja dengan objek dengan benar. Header objek menyertakan "kata tanda", yang terlihat seperti ini: 
https://edu.netbeans.org/contrib/slides/java-overview-and-java-se6.pdf
public class HelloWorld{
public static void main(String []args){
Object object = new Object();
synchronized(object) {
System.out.println("Hello World");
}
}
}
Di sini, utas saat ini (utas tempat baris kode ini dieksekusi) menggunakan synchronized
kata kunci untuk mencoba menggunakan monitor yang terkait denganobject"\
variabel untuk mendapatkan/memperoleh kunci. Jika tidak ada orang lain yang memperebutkan monitor (yaitu tidak ada orang lain yang menjalankan kode tersinkronisasi menggunakan objek yang sama), maka Java dapat mencoba melakukan pengoptimalan yang disebut "penguncian bias". Tag yang relevan dan catatan tentang utas mana yang memiliki kunci monitor ditambahkan ke kata tanda di header objek. Ini mengurangi biaya overhead yang diperlukan untuk mengunci monitor. Jika monitor sebelumnya dimiliki oleh utas lain, penguncian seperti itu tidak cukup. JVM beralih ke jenis penguncian berikutnya: "penguncian dasar". Ini menggunakan operasi bandingkan dan tukar (CAS). Terlebih lagi, kata tanda header objek itu sendiri tidak lagi menyimpan kata tanda, melainkan referensi ke tempat penyimpanannya, dan tag berubah sehingga JVM memahami bahwa kita menggunakan penguncian dasar. Jika beberapa utas bersaing (bersaing) untuk monitor (satu telah memperoleh kunci, dan yang kedua menunggu kunci dilepaskan), maka tag dalam kata tanda berubah, dan kata tanda sekarang menyimpan referensi ke monitor sebagai objek — beberapa entitas internal JVM. Sebagaimana dinyatakan dalam JDK Enchancement Proposal (JEP), situasi ini memerlukan ruang di area memori Native Heap untuk menyimpan entitas ini. Referensi ke lokasi memori entitas internal ini akan disimpan dalam kata tanda header objek. Jadi, monitor sebenarnya adalah mekanisme untuk menyinkronkan akses ke sumber daya bersama di antara banyak utas. JVM beralih di antara beberapa implementasi mekanisme ini. Jadi, untuk mempermudah, saat berbicara tentang monitor, sebenarnya kita sedang berbicara tentang kunci. dan sedetik menunggu kunci dilepaskan), kemudian tag pada kata tanda berubah, dan kata tanda sekarang menyimpan referensi ke monitor sebagai objek - beberapa entitas internal JVM. Sebagaimana dinyatakan dalam JDK Enchancement Proposal (JEP), situasi ini memerlukan ruang di area memori Native Heap untuk menyimpan entitas ini. Referensi ke lokasi memori entitas internal ini akan disimpan dalam kata tanda header objek. Jadi, monitor sebenarnya adalah mekanisme untuk menyinkronkan akses ke sumber daya bersama di antara banyak utas. JVM beralih di antara beberapa implementasi mekanisme ini. Jadi, untuk mempermudah, saat berbicara tentang monitor, sebenarnya kita sedang berbicara tentang kunci. dan sedetik menunggu kunci dilepaskan), kemudian tag pada kata tanda berubah, dan kata tanda sekarang menyimpan referensi ke monitor sebagai objek - beberapa entitas internal JVM. Sebagaimana dinyatakan dalam JDK Enchancement Proposal (JEP), situasi ini memerlukan ruang di area memori Native Heap untuk menyimpan entitas ini. Referensi ke lokasi memori entitas internal ini akan disimpan dalam kata tanda header objek. Jadi, monitor sebenarnya adalah mekanisme untuk menyinkronkan akses ke sumber daya bersama di antara banyak utas. JVM beralih di antara beberapa implementasi mekanisme ini. Jadi, untuk mempermudah, saat berbicara tentang monitor, sebenarnya kita sedang berbicara tentang kunci. dan kata tanda sekarang menyimpan referensi ke monitor sebagai objek — beberapa entitas internal JVM. Sebagaimana dinyatakan dalam JDK Enchancement Proposal (JEP), situasi ini memerlukan ruang di area memori Native Heap untuk menyimpan entitas ini. Referensi ke lokasi memori entitas internal ini akan disimpan dalam kata tanda header objek. Jadi, monitor sebenarnya adalah mekanisme untuk menyinkronkan akses ke sumber daya bersama di antara banyak utas. JVM beralih di antara beberapa implementasi mekanisme ini. Jadi, untuk mempermudah, saat berbicara tentang monitor, sebenarnya kita sedang berbicara tentang kunci. dan kata tanda sekarang menyimpan referensi ke monitor sebagai objek — beberapa entitas internal JVM. Sebagaimana dinyatakan dalam JDK Enchancement Proposal (JEP), situasi ini memerlukan ruang di area memori Native Heap untuk menyimpan entitas ini. Referensi ke lokasi memori entitas internal ini akan disimpan dalam kata tanda header objek. Jadi, monitor sebenarnya adalah mekanisme untuk menyinkronkan akses ke sumber daya bersama di antara banyak utas. JVM beralih di antara beberapa implementasi mekanisme ini. Jadi, untuk mempermudah, saat berbicara tentang monitor, sebenarnya kita sedang berbicara tentang kunci. Referensi ke lokasi memori entitas internal ini akan disimpan dalam kata tanda header objek. Jadi, monitor sebenarnya adalah mekanisme untuk menyinkronkan akses ke sumber daya bersama di antara banyak utas. JVM beralih di antara beberapa implementasi mekanisme ini. Jadi, untuk mempermudah, saat berbicara tentang monitor, sebenarnya kita sedang berbicara tentang kunci. Referensi ke lokasi memori entitas internal ini akan disimpan dalam kata tanda header objek. Jadi, monitor sebenarnya adalah mekanisme untuk menyinkronkan akses ke sumber daya bersama di antara banyak utas. JVM beralih di antara beberapa implementasi mekanisme ini. Jadi, untuk mempermudah, saat berbicara tentang monitor, sebenarnya kita sedang berbicara tentang kunci. 
Disinkronkan (menunggu kunci)
Seperti yang kita lihat sebelumnya, konsep "blok tersinkronisasi" (atau "bagian penting") terkait erat dengan konsep monitor. Lihatlah contoh:
public static void main(String[] args) throws InterruptedException {
Object lock = new Object();
Runnable task = () -> {
synchronized(lock) {
System.out.println("thread");
}
};
Thread th1 = new Thread(task);
th1.start();
synchronized(lock) {
for (int i = 0; i < 8; i++) {
Thread.currentThread().sleep(1000);
System.out.print(" " + i);
}
System.out.println(" ...");
}
}
Di sini, utas utama pertama-tama meneruskan objek tugas ke utas baru, lalu segera memperoleh kunci dan melakukan operasi panjang dengannya (8 detik). Selama ini tugas tidak bisa dilanjutkan, karena tidak bisa masuk synchronized
blok, karena kunci sudah didapat. Jika utas tidak bisa mendapatkan kunci, itu akan menunggu monitor. Segera setelah mendapat kunci, itu akan melanjutkan eksekusi. Saat utas keluar dari monitor, utas itu melepaskan kuncinya. Di JVisualVM, tampilannya seperti ini: 
th1.getState()
pernyataan dalam for loop akan mengembalikan BLOCKED , karena selama loop berjalan, lock
monitor objek ditempati oleh main
utas, dan th1
utas diblokir dan tidak dapat dilanjutkan hingga kunci dilepaskan. Selain blok yang disinkronkan, seluruh metode dapat disinkronkan. Misalnya, inilah metode dari HashTable
kelas:
public synchronized int size() {
return count;
}
Metode ini akan dieksekusi hanya oleh satu utas pada waktu tertentu. Apakah kita benar-benar membutuhkan kunci? Ya, kami membutuhkannya. Dalam kasus metode instan, objek "ini" (objek saat ini) bertindak sebagai kunci. Ada diskusi menarik tentang topik ini di sini: Apakah ada keuntungan menggunakan Metode Tersinkronisasi daripada Blok Tersinkronisasi? . Jika metodenya statis, maka kuncinya bukan objek "ini" (karena tidak ada objek "ini" untuk metode statis), melainkan objek Kelas (misalnya, ) Integer.class
.
Tunggu (menunggu monitor). notify() dan notifyAll() metode
Kelas Thread memiliki metode menunggu lain yang diasosiasikan dengan monitor. Tidak sepertisleep()
and join()
, metode ini tidak bisa dipanggil begitu saja. Namanya adalah wait()
. Metode wait
dipanggil pada objek yang terkait dengan monitor yang ingin kita tunggu. Mari kita lihat contohnya:
public static void main(String []args) throws InterruptedException {
Object lock = new Object();
// The task object will wait until it is notified via lock
Runnable task = () -> {
synchronized(lock) {
try {
lock.wait();
} catch(InterruptedException e) {
System.out.println("interrupted");
}
}
// After we are notified, we will wait until we can acquire the lock
System.out.println("thread");
};
Thread taskThread = new Thread(task);
taskThread.start();
// We sleep. Then we acquire the lock, notify, and release the lock
Thread.currentThread().sleep(3000);
System.out.println("main");
synchronized(lock) {
lock.notify();
}
}
Di JVisualVM, tampilannya seperti ini: 
wait()
dan notify()
dikaitkan dengan java.lang.Object
. Mungkin tampak aneh bahwa metode terkait utas ada di Object
kelas. Tapi alasan untuk itu sekarang terungkap. Anda akan ingat bahwa setiap objek di Java memiliki header. Header berisi berbagai informasi tata graha, termasuk informasi tentang monitor, yaitu status kunci. Ingat, setiap objek, atau turunan dari kelas, dikaitkan dengan entitas internal di JVM, yang disebut kunci atau monitor intrinsik. Pada contoh di atas, kode untuk objek tugas menunjukkan bahwa kita memasukkan blok tersinkronisasi untuk monitor yang terkait dengan lock
objek tersebut. Jika kami berhasil mendapatkan kunci untuk monitor ini, makawait()
disebut. Utas yang menjalankan tugas akan melepaskan lock
monitor objek, tetapi akan memasuki antrean utas menunggu pemberitahuan dari lock
monitor objek. Antrian utas ini disebut SET TUNGGU, yang lebih tepat mencerminkan tujuannya. Artinya, ini lebih merupakan kumpulan daripada antrian. Utas main
membuat utas baru dengan objek tugas, memulainya, dan menunggu 3 detik. Hal ini sangat mungkin membuat utas baru dapat memperoleh kunci sebelum utas main
, dan masuk ke antrean monitor. Setelah itu, main
utas itu sendiri memasuki lock
blok objek yang disinkronkan dan melakukan pemberitahuan utas menggunakan monitor. Setelah pemberitahuan dikirim, main
utas melepaskanlock
monitor objek, dan utas baru, yang sebelumnya menunggu lock
monitor objek dirilis, melanjutkan eksekusi. Dimungkinkan untuk mengirim pemberitahuan hanya ke satu utas ( notify()
) atau secara bersamaan ke semua utas dalam antrean ( notifyAll()
). Baca lebih lanjut di sini: Perbedaan antara notify() dan notifyAll() di Java . Penting untuk diperhatikan bahwa urutan notifikasi tergantung pada bagaimana JVM diimplementasikan. Baca lebih lanjut di sini: Bagaimana cara mengatasi kelaparan dengan notify dan notifyAll? . Sinkronisasi dapat dilakukan tanpa menentukan objek. Anda dapat melakukan ini saat seluruh metode disinkronkan daripada satu blok kode. Misalnya, untuk metode statis, kuncinya akan berupa objek Kelas (diperoleh melalui .class
):
public static synchronized void printA() {
System.out.println("A");
}
public static void printB() {
synchronized(HelloWorld.class) {
System.out.println("B");
}
}
Dalam hal penggunaan kunci, kedua metode itu sama. Jika suatu metode tidak statis, maka sinkronisasi akan dilakukan dengan menggunakan current instance
, yaitu menggunakan this
. Omong-omong, kami katakan sebelumnya Anda dapat menggunakan getState()
metode ini untuk mendapatkan status utas. Misalnya, untuk utas dalam antrean yang menunggu monitor, statusnya akan WAITING atau TIMED_WAITING, jika wait()
metode tersebut menetapkan batas waktu. 
https://stackoverflow.com/questions/36425942/what-is-the-lifecycle-of-thread-in-java
Siklus hidup benang
Sepanjang hidupnya, status utas berubah. Faktanya, perubahan ini terdiri dari siklus hidup utas. Segera setelah utas dibuat, statusnya adalah BARU. Dalam keadaan ini, utas baru belum berjalan dan penjadwal utas Java belum mengetahui apa pun tentangnya. Agar penjadwal utas mempelajari tentang utas, Anda harus memanggilthread.start()
metode. Kemudian utas akan bertransisi ke status DAPAT DIJALANKAN. Internet memiliki banyak diagram yang salah yang membedakan antara status "Dapat dijalankan" dan "Berjalan". Tapi ini kesalahan, karena Java tidak membedakan antara "ready to work" (runnable) dan "working" (running). Saat utas hidup tetapi tidak aktif (tidak dapat dijalankan), utas berada dalam salah satu dari dua status:
- DIBLOKIR — menunggu untuk memasuki bagian kritis, yaitu
synchronized
blok. - MENUNGGU — menunggu utas lain untuk memenuhi beberapa kondisi.
getState()
metode ini. Utas juga memiliki isAlive()
metode, yang mengembalikan true jika utas tidak DIHENTIKAN.
LockSupport dan parkir utas
Dimulai dengan Java 1.6, mekanisme menarik yang disebut LockSupport muncul.
park()
metode segera kembali jika izin tersedia, menggunakan izin dalam proses. Jika tidak, itu memblokir. Memanggil unpark
metode membuat izin tersedia jika belum tersedia. Hanya ada 1 izin. Dokumentasi Java untuk LockSupport
merujuk ke Semaphore
kelas. Mari kita lihat contoh sederhana:
import java.util.concurrent.Semaphore;
public class HelloWorldApp{
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(0);
try {
semaphore.acquire();
} catch (InterruptedException e) {
// Request the permit and wait until we get it
e.printStackTrace();
}
System.out.println("Hello, World!");
}
}
Kode ini akan selalu menunggu, karena sekarang semafor memiliki 0 izin. Dan ketika acquire()
dipanggil dalam kode (yaitu meminta izin), utas menunggu hingga menerima izin. Karena kita sedang menunggu, kita harus menanganinya InterruptedException
. Menariknya, semafor mendapat status utas terpisah. Jika kita melihat di JVisualVM, kita akan melihat bahwa statusnya bukan "Tunggu", tetapi "Park". 
public static void main(String[] args) throws InterruptedException {
Runnable task = () -> {
// Park the current thread
System.err.println("Will be Parked");
LockSupport.park();
// As soon as we are unparked, we will start to act
System.err.println("Unparked");
};
Thread th = new Thread(task);
th.start();
Thread.currentThread().sleep(2000);
System.err.println("Thread state: " + th.getState());
LockSupport.unpark(th);
Thread.currentThread().sleep(2000);
}
Status utas akan MENUNGGU, tetapi JVisualVM membedakan antara wait
dari synchronized
kata kunci dan park
dari LockSupport
kelas. Mengapa ini LockSupport
sangat penting? Kami kembali ke dokumentasi Java dan melihat status WAITING thread. Seperti yang Anda lihat, hanya ada tiga cara untuk masuk ke dalamnya. Dua di antaranya adalah wait()
dan join()
. Dan yang ketiga adalah LockSupport
. Di Java, kunci juga dapat dibangun di LockSuppor
t dan menawarkan alat dengan tingkat yang lebih tinggi. Mari kita coba gunakan salah satunya. Sebagai contoh, lihatlah ReentrantLock
:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class HelloWorld{
public static void main(String []args) throws InterruptedException {
Lock lock = new ReentrantLock();
Runnable task = () -> {
lock.lock();
System.out.println("Thread");
lock.unlock();
};
lock.lock();
Thread th = new Thread(task);
th.start();
System.out.println("main");
Thread.currentThread().sleep(2000);
lock.unlock();
}
}
Sama seperti pada contoh sebelumnya, semuanya sederhana di sini. Objek lock
menunggu seseorang melepaskan sumber daya bersama. Jika kita melihat di JVisualVM, kita akan melihat bahwa utas baru akan diparkir hingga utas main
melepaskan kuncinya. Anda dapat membaca lebih lanjut tentang kunci di sini: Java 8 StampedLocks vs. ReadWriteLocks dan Synchronized and Lock API in Java. Untuk lebih memahami bagaimana kunci diimplementasikan, ada gunanya membaca tentang Phaser di artikel ini: Panduan untuk Java Phaser . Dan berbicara tentang berbagai sinkronisasi, Anda harus membaca artikel DZone di The Java Synchronizers.
Kesimpulan
Dalam ulasan ini, kami memeriksa cara utama utas berinteraksi di Jawa. Material tambahan:- Lebih baik bersama: Java dan kelas Thread. Bagian I — Utas eksekusi
- https://dzone.com/articles/the-java-synchronizers
- https://www.javatpoint.com/java-multithreading-interview-questions
GO TO FULL VERSION