Halo! Saat mempelajari multithreading di JavaRush, Anda sering menemukan konsep “mutex” dan “monitor”. Bisakah Anda sekarang, tanpa mengintip, menjawab perbedaannya? :) Jika Anda bisa, bagus sekali! Jika tidak (dan paling sering ini terjadi) - tidak heran. Konsep "mutex" dan "monitor" memang saling berkaitan. Selain itu, saat membaca ceramah dan menonton video tentang multithreading pada sumber daya eksternal di Internet, Anda akan menemukan konsep serupa lainnya - “semaphore”. Fungsionalitasnya juga sebagian besar mirip dengan monitor dan mutex. Oleh karena itu, mari kita pahami ketiga istilah ini, lihat beberapa contoh, dan terakhir susun di kepala kita pemahaman tentang perbedaannya satu sama lain :)
Kami akan menyederhanakan persyaratannya sedikit untuk pemahaman yang lebih baik. Bayangkan kita memiliki 5 filsuf yang butuh makan siang. Pada saat yang sama, kami memiliki satu meja, dan tidak lebih dari dua orang dapat berada di meja tersebut pada waktu yang bersamaan. Tugas kita adalah memberi makan semua filsuf. Tak satu pun dari mereka harus kelaparan, dan mereka juga tidak boleh “menghalangi” satu sama lain ketika mencoba untuk duduk di meja (kita harus menghindari kebuntuan). Seperti inilah kelas filsuf kita nantinya:
muteks
Mutex adalah objek khusus untuk menyinkronkan thread. Itu "melekat" ke setiap objek di Java - Anda sudah mengetahuinya :) Tidak masalah apakah Anda menggunakan kelas standar atau membuat kelas Anda sendiri, misalnya,Cat
dan Dog
: semua objek dari semua kelas memiliki mutex . Nama "mutex" berasal dari bahasa Inggris "MUTual EXclusion" - "mutual exclusion", dan ini mencerminkan tujuannya dengan sempurna. Seperti yang kami katakan di salah satu kuliah sebelumnya, tugas mutex adalah menyediakan mekanisme sehingga hanya satu thread yang memiliki akses ke suatu objek pada waktu tertentu . Analogi populer untuk mutex dalam kehidupan nyata adalah “contoh toilet”. Ketika seseorang memasuki toilet, dia mengunci pintu dari dalam. Toilet bertindak sebagai objek yang dapat diakses oleh banyak thread. Kunci pintu toilet berperan sebagai mutex, dan antrian orang di luar berperan sebagai benang. Kunci pintunya adalah mutex toilet: yang memastikan hanya satu orang yang bisa berada di dalam pada satu waktu. Dengan kata lain, hanya satu thread dalam satu waktu yang dapat bekerja pada sumber daya bersama. Upaya thread lain (orang) untuk mengakses sumber daya yang ditempati akan gagal. Mutex memiliki beberapa fitur penting. Pertama , hanya ada dua keadaan yang memungkinkan - “bebas” dan “sibuk”. Hal ini memudahkan untuk memahami cara kerjanya: persamaan dapat digambar dengan variabel Boolean benar/salah atau sistem bilangan biner 1/0. Kedua , negara tidak dapat dikontrol secara langsung. Tidak ada mekanisme di Java yang memungkinkan Anda mengambil objek secara eksplisit, mendapatkan mutexnya, dan menetapkan status yang diinginkan padanya. Dengan kata lain, Anda tidak dapat melakukan sesuatu seperti:
Object myObject = new Object();
Mutex mutex = myObject.getMutex();
mutex.free();
Dengan demikian, mutex objek tidak dapat dilepaskan. Hanya mesin Java yang memiliki akses langsung ke sana. Pemrogram bekerja dengan mutex menggunakan alat bahasa.
Memantau
Monitor adalah “tambahan” tambahan untuk mutex. Faktanya, monitor adalah sepotong kode yang “tidak terlihat” oleh pemrogram . Berbicara tentang mutex tadi, kami memberikan contoh sederhana:public class Main {
private Object obj = new Object();
public void doSomething() {
//...some logic available to all threads
synchronized (obj) {
//logic that is only available to one thread at a time
}
}
}
Dalam blok kode yang ditandai dengan kata tersebut synchronized
, mutex objek kita ditangkap obj
. Oke, penangkapan memang terjadi, tapi bagaimana sebenarnya “mekanisme pertahanan” tersebut dicapai? synchronized
Mengapa utas lain tidak bisa masuk ke dalam blok ketika mereka melihat sebuah kata ? Monitorlah yang menciptakan mekanisme perlindungan! Kompiler mengubah kata tersebut synchronized
menjadi beberapa bagian kode khusus. Sekali lagi mari kita kembali ke contoh kita dengan metode ini doSomething()
dan menambahkannya:
public class Main {
private Object obj = new Object();
public void doSomething() {
//...some logic available to all threads
//logic that is only available to one thread at a time
synchronized (obj) {
/*выполнить важную работу, при которой доступ к an objectу
должен быть только у одного потока*/
obj.someImportantMethod();
}
}
}
Inilah yang akan terjadi "di balik terpal" program kita setelah kompiler mengonversi kode ini:
public class Main {
private Object obj = new Object();
public void doSomething() throws InterruptedException {
//...some logic available to all threads
//логика, которая одновременно доступна только для одного потока:
/*до тех пор, пока мьютекс an object занят -
любой другой поток (кроме того, который его захватил), спит*/
while (obj.getMutex().isBusy()) {
Thread.sleep(1);
}
//пометить мьютекс an object How занятый
obj.getMutex().isBusy() = true;
/*выполнить важную работу, при которой доступ к an objectу
должен быть только у одного потока*/
obj.someImportantMethod();
//освободить мьютекс an object
obj.getMutex().isBusy() = false;
}
}
Contohnya tentu saja tidak nyata. Di sini, dengan menggunakan kode mirip Java, kami mencoba merefleksikan apa yang terjadi saat ini di dalam mesin Java. Namun, kodesemu ini memberikan pemahaman yang baik tentang apa yang sebenarnya terjadi dengan objek dan thread di dalam blok synchronized
dan bagaimana kompiler mengubah kata ini menjadi beberapa perintah yang “tidak terlihat” oleh pemrogram. Intinya, monitor di Java dinyatakan menggunakan katasynchronized
. Semua kode yang muncul sebagai pengganti kata synchronized
pada contoh terakhir adalah monitor.
Tiang sinyal
Kata lain yang Anda temui saat mempelajari multithreading sendiri adalah “semaphore”. Mari kita cari tahu apa itu dan apa bedanya dengan monitor dan mutex. Semaphore adalah sarana untuk menyinkronkan akses ke sumber daya. Keunikannya adalah ia menggunakan penghitung saat membuat mekanisme sinkronisasi. Penghitung memberi tahu kita berapa banyak thread yang dapat mengakses sumber daya bersama secara bersamaan. Semaphore di Java diwakili oleh kelasSemaphore
. Saat membuat objek semaphore, kita dapat menggunakan konstruktor berikut:
Semaphore(int permits)
Semaphore(int permits, boolean fair)
Kami meneruskan ke konstruktor:
-
int permits
— nilai penghitung awal dan maksimum. Artinya, berapa banyak thread yang dapat mengakses sumber daya bersama secara bersamaan; -
boolean fair
- untuk menetapkan urutan thread yang akan menerima akses. Jikafair
= true , akses diberikan ke thread yang menunggu sesuai urutan permintaannya. Jika salah , urutannya akan ditentukan oleh penjadwal thread.
class Philosopher extends Thread {
private Semaphore sem;
// поел ли философ
private boolean full = false;
private String name;
Philosopher(Semaphore sem, String name) {
this.sem=sem;
this.name=name;
}
public void run()
{
try
{
// если философ еще не ел
if (!full) {
//Запрашиваем у семафора разрешение на выполнение
sem.acquire();
System.out.println (name + " садится за стол");
// философ ест
sleep(300);
full = true;
System.out.println (name + " поел! Он выходит из-за стола");
sem.release();
// философ ушел, освободив место другим
sleep(300);
}
}
catch(InterruptedException e) {
System.out.println ("What-то пошло не так!");
}
}
}
Dan berikut ini kode untuk menjalankan program kita:
public class Main {
public static void main(String[] args) {
Semaphore sem = new Semaphore(2);
new Philosopher(sem,"Сократ").start();
new Philosopher(sem,"Платон").start();
new Philosopher(sem,"Аристотель").start();
new Philosopher(sem,"Фалес").start();
new Philosopher(sem,"Пифагор").start();
}
}
Kami membuat semaphore dengan hitungan 2 untuk memenuhi syarat bahwa hanya dua filsuf yang bisa makan pada saat yang bersamaan. Artinya, hanya dua thread yang dapat bekerja secara bersamaan, karena kelas kita Philosopher
diwarisi dari Thread
! Kelas acquire()
dan metode mengontrol penghitung izinnya. Metode ini meminta izin untuk mengakses sumber daya dari semaphore. Jika penghitung > 0, izin diberikan dan penghitung dikurangi 1. Metode "melepaskan" izin yang diberikan sebelumnya dan mengembalikannya ke penghitung (menambah penghitung hibah semafor sebesar 1). Apa yang kita dapatkan ketika kita menjalankan program tersebut? Apakah masalahnya sudah terpecahkan? Akankah para filosof kita berjuang sambil menunggu giliran? :) Ini adalah output konsol yang kami terima: Socrates duduk di meja Plato duduk di meja yang Socrates makan! Dia meninggalkan meja. Plato sudah makan! Dia meninggalkan meja yang diduduki Aristoteles di meja yang diduduki Pythagoras di meja yang telah dimakan Aristoteles! Dia meninggalkan meja yang telah dimakan Pythagoras! Dia meninggalkan meja yang Thales duduk di meja yang Thales makan! Dia meninggalkan meja. Kita berhasil! Dan meskipun Thales harus makan sendirian, menurut saya dia tidak marah pada kami :) Anda mungkin telah memperhatikan beberapa kesamaan antara mutex dan semaphore. Secara umum, mereka memiliki tujuan yang sama: untuk menyinkronkan akses ke beberapa sumber daya. Satu-satunya perbedaan adalah bahwa mutex suatu objek hanya dapat diperoleh oleh satu thread pada satu waktu, sedangkan dalam kasus semaphore, penghitung thread digunakan, dan beberapa dari mereka dapat mengakses sumber daya sekaligus. Dan ini bukan hanya kesamaan yang kebetulan :) Faktanya, mutex adalah semaphore satu tempat . Artinya, ini adalah semafor yang penghitungnya awalnya disetel ke 1. Disebut juga "semafor biner" karena penghitungnya hanya dapat memiliki 2 nilai - 1 ("bebas") dan 0 ("sibuk"). Itu saja! Seperti yang Anda lihat, semuanya ternyata tidak terlalu membingungkan :) Sekarang, jika Anda ingin mempelajari topik multithreading lebih detail di Internet, akan lebih mudah bagi Anda untuk menavigasi konsepnya. Sampai jumpa di pelajaran selanjutnya! release()
Semaphore
acquire()
release()
GO TO FULL VERSION