JavaRush /Blog Java /Random-MS /Penyegerakan benang. Pengendali disegerakkan di Jawa

Penyegerakan benang. Pengendali disegerakkan di Jawa

Diterbitkan dalam kumpulan
hello! Hari ini kita akan terus mempertimbangkan ciri pengaturcaraan berbilang benang dan bercakap tentang penyegerakan benang.
Penyegerakan benang.  Operator disegerakkan - 1
Apakah "penyegerakan"? Di luar alam pengaturcaraan, ini merujuk kepada beberapa jenis persediaan yang membolehkan dua peranti atau program berfungsi bersama. Contohnya, telefon pintar dan komputer boleh disegerakkan dengan akaun Google, dan akaun peribadi di tapak web boleh disegerakkan dengan akaun di rangkaian sosial untuk log masuk menggunakan akaun tersebut. Penyegerakan benang mempunyai makna yang sama: ia menyediakan cara utas berinteraksi antara satu sama lain. Dalam kuliah sebelumnya, benang kami hidup dan berfungsi secara berasingan antara satu sama lain. Seorang sedang mengira sesuatu, yang kedua sedang tidur, yang ketiga sedang memaparkan sesuatu pada konsol, tetapi mereka tidak berinteraksi antara satu sama lain. Dalam program sebenar situasi sedemikian jarang berlaku. Beberapa utas boleh berfungsi secara aktif, contohnya, dengan set data yang sama dan mengubah sesuatu di dalamnya. Ini menimbulkan masalah. Bayangkan berbilang benang sedang menulis teks ke lokasi yang sama, seperti fail teks atau konsol. Fail atau konsol ini dalam kes ini menjadi sumber kongsi. Benang tidak tahu tentang kewujudan satu sama lain, jadi mereka hanya menulis semua yang mereka boleh uruskan dalam masa yang diperuntukkan oleh penjadual benang kepada mereka. Dalam syarahan kursus baru-baru ini, kami mempunyai contoh perkara ini akan membawa kepada, mari kita ingat: Penyegerakan benang.  Pengendali disegerakkan - 2Sebabnya terletak pada fakta bahawa utas berfungsi dengan sumber yang dikongsi, konsol, tanpa menyelaraskan tindakan antara satu sama lain. Jika penjadual benang telah memperuntukkan masa untuk Thread-1, ia segera menulis segala-galanya ke konsol. Perkara lain yang telah berjaya ditulis atau belum berjaya ditulis adalah tidak penting. Hasilnya, seperti yang anda lihat, adalah bencana. Oleh itu, dalam pengaturcaraan berbilang benang, mutex konsep khas telah diperkenalkan (dari bahasa Inggeris "mutex", "mutual exclusion" - "mutual exclusion") . Tujuan mutex adalah untuk menyediakan mekanisme supaya hanya satu utas mempunyai akses kepada objek pada masa tertentu. Jika Thread-1 telah memperoleh mutex objek A, thread lain tidak akan mempunyai akses kepadanya untuk mengubah apa-apa di dalamnya. Sehingga mutex objek A dilepaskan, benang yang tinggal akan terpaksa menunggu. Contoh kehidupan sebenar: bayangkan anda dan 10 orang asing yang lain menyertai latihan. Anda perlu bergilir-gilir menyatakan idea dan membincangkan sesuatu. Tetapi, memandangkan anda bertemu untuk pertama kali, supaya tidak mengganggu satu sama lain secara berterusan dan tidak menjadi keriuhan, anda menggunakan peraturan "bola bercakap": hanya seorang yang boleh bercakap - orang yang mempunyai bola. tangan dia. Dengan cara ini perbincangan ternyata mencukupi dan membuahkan hasil. Jadi, mutex, pada dasarnya, adalah seperti bola. Jika mutex objek berada di tangan satu utas, utas lain tidak akan dapat mengakses objek tersebut. Anda tidak perlu melakukan apa-apa untuk mencipta mutex: ia sudah dibina ke dalam class Object, yang bermaksud setiap objek di Java memilikinya.

Cara pengendali yang disegerakkan berfungsi dalam Java

Mari kita berkenalan dengan kata kunci baharu - disegerakkan . Ia menandakan bahagian tertentu kod kami. Jika blok kod ditandakan dengan kata kunci yang disegerakkan, ini bermakna blok itu hanya boleh dilaksanakan oleh satu utas pada satu masa. Penyegerakan boleh dilaksanakan dengan cara yang berbeza. Sebagai contoh, buat keseluruhan kaedah yang disegerakkan:
public synchronized void doSomething() {

   //...method logic
}
Atau tulis blok kod di mana penyegerakan dijalankan pada beberapa objek:
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
       }
   }
}
Maksudnya mudah. Jika satu utas memasuki blok kod yang ditandakan dengan perkataan disegerakkan, ia serta-merta memperoleh mutex objek, dan semua utas lain yang cuba memasuki blok atau kaedah yang sama terpaksa menunggu sehingga utas sebelumnya menyelesaikan kerjanya dan melepaskan pantau. Penyegerakan benang.  Operator disegerakkan - 3By the way! Dalam kuliah kursus anda telah melihat contoh yang disegerakkan, tetapi ia kelihatan berbeza:
public void swap()
{
   synchronized (this)
   {
       //...method logic
   }
}
Topik ini baru untuk anda, dan sudah tentu akan ada kekeliruan dengan sintaks pada mulanya. Oleh itu, ingatlah segera agar tidak keliru nanti dalam kaedah penulisan. Kedua-dua kaedah penulisan ini bermaksud perkara yang sama:
public void swap() {

   synchronized (this)
   {
       //...method logic
   }
}


public synchronized void swap() {

   }
}
Dalam kes pertama, anda membuat blok kod yang disegerakkan serta-merta selepas memasukkan kaedah. Ia disegerakkan oleh objek this, iaitu, oleh objek semasa. Dan dalam contoh kedua anda meletakkan perkataan disegerakkan pada keseluruhan kaedah. Tidak ada lagi keperluan untuk menunjukkan secara eksplisit sebarang objek yang penyegerakan dijalankan. Setelah keseluruhan kaedah ditandakan dengan perkataan, kaedah ini akan disegerakkan secara automatik untuk semua objek kelas. Janganlah kita mendalami perbincangan kaedah mana yang lebih baik. Buat masa ini, pilih yang paling anda suka :) Perkara utama adalah untuk diingat: anda boleh mengisytiharkan kaedah disegerakkan hanya apabila semua logik di dalamnya dilaksanakan oleh satu utas pada masa yang sama. Sebagai contoh, dalam kes ini doSomething()ia akan menjadi ralat untuk membuat kaedah disegerakkan:
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
       }
   }
}
Seperti yang anda lihat, sekeping kaedah mengandungi logik yang mana penyegerakan tidak diperlukan. Kod di dalamnya boleh dilaksanakan oleh beberapa utas secara serentak, dan semua tempat kritikal diperuntukkan kepada blok disegerakkan yang berasingan. Dan seketika. Mari lihat di bawah mikroskop pada contoh kami dari kuliah dengan pertukaran nama:
public void swap()
{
   synchronized (this)
   {
       //...method logic
   }
}
Sila ambil perhatian: penyegerakan dijalankan menggunakan this. Iaitu, untuk objek tertentu MyClass. Bayangkan kita mempunyai 2 utas ( Thread-1dan Thread-2) dan hanya satu objek MyClass myClass. Dalam kes ini, jika Thread-1kaedah dipanggil myClass.swap(), mutex objek akan sibuk dan Thread-2apabila anda cuba memanggilnya, myClass.swap()ia akan tergantung menunggu mutex menjadi bebas. Jika kita mempunyai 2 utas dan 2 objek MyClass- myClass1dan myClass2- pada objek yang berbeza, utas kami boleh dengan mudah melaksanakan kaedah yang disegerakkan secara serentak. Benang pertama melakukan:
myClass1.swap();
Yang kedua melakukan:
myClass2.swap();
Dalam kes ini, kata kunci yang disegerakkan di dalam kaedah swap()tidak akan menjejaskan pengendalian program, kerana penyegerakan dijalankan pada objek tertentu. Dan dalam kes kedua, kita mempunyai 2 objek. Oleh itu, benang tidak menimbulkan masalah antara satu sama lain. Lagipun, dua objek mempunyai 2 mutex yang berbeza, dan penangkapan mereka tidak bergantung antara satu sama lain.

Ciri-ciri penyegerakan dalam kaedah statik

Tetapi bagaimana jika anda perlu menyegerakkan kaedah statik?
class MyClass {
   private static String name1 = "Olya";
   private static String name2 = "Lena";

   public static synchronized void swap() {
       String s = name1;
       name1 = name2;
       name2 = s;
   }

}
Tidak jelas apa yang akan berfungsi sebagai mutex dalam kes ini. Lagipun, kami telah memutuskan bahawa setiap objek mempunyai mutex. Tetapi masalahnya ialah untuk memanggil kaedah statik MyClass.swap()kita tidak memerlukan objek: kaedahnya statik! Jadi, apa yang seterusnya? :/ Sebenarnya, tiada masalah dengan ini. Pencipta Java telah mengurus segala-galanya :) Jika kaedah yang mengandungi logik "berbilang benang" kritikal adalah statik, penyegerakan akan dijalankan mengikut kelas. Untuk lebih jelas, kod di atas boleh ditulis semula sebagai:
class MyClass {
   private static String name1 = "Olya";
   private static String name2 = "Lena";

   public static void swap() {

       synchronized (MyClass.class) {
           String s = name1;
           name1 = name2;
           name2 = s;
       }
   }

}
Pada dasarnya, anda boleh memikirkan perkara ini sendiri: kerana tiada objek, maka mekanisme penyegerakan mesti entah bagaimana "dihubungkan" ke dalam kelas itu sendiri. Begitulah keadaannya: anda juga boleh menyegerakkan merentas kelas.
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION