CodeGym /Blog Java /rawak /Penyegerakan benang. Pengendali yang disegerakkan
John Squirrels
Tahap
San Francisco

Penyegerakan benang. Pengendali yang disegerakkan

Diterbitkan dalam kumpulan
Hai! Hari ini kita akan terus mempertimbangkan ciri pengaturcaraan berbilang benang dan bercakap tentang penyegerakan benang. Penyegerakan benang.  Pengendali yang disegerakkan - 1

Apakah penyegerakan dalam Java?

Di luar domain pengaturcaraan, ia membayangkan susunan yang membolehkan dua peranti atau program berfungsi bersama. Sebagai contoh, telefon pintar dan komputer boleh disegerakkan dengan akaun Google dan akaun tapak web boleh disegerakkan dengan akaun rangkaian sosial supaya anda boleh menggunakannya untuk log masuk. satu sama lain. Dalam pelajaran sebelumnya, benang kami hidup dan berfungsi secara berasingan antara satu sama lain. Seorang melakukan pengiraan, yang kedua tidur dan yang ketiga memaparkan sesuatu pada konsol, tetapi mereka tidak berinteraksi. Dalam program sebenar, situasi sedemikian jarang berlaku. Berbilang benang boleh berfungsi dengan aktif dan mengubah suai set data yang sama. Ini menimbulkan masalah. Bayangkan beberapa utas menulis teks ke tempat yang sama, contohnya, ke fail teks atau konsol. Dalam kes ini, fail atau konsol menjadi sumber kongsi. Benang tidak menyedari kewujudan satu sama lain, jadi mereka hanya menulis semua yang mereka boleh dalam masa yang diperuntukkan kepada mereka oleh penjadual benang. Dalam pelajaran baru-baru ini, kami melihat contoh ke mana hal ini membawanya. Mari kita ingat sekarang: Penyegerakan benang.  Pengendali yang disegerakkan - 2Sebabnya terletak pada fakta bahawa utas berfungsi dengan sumber yang dikongsi (konsol) tanpa menyelaraskan tindakan mereka antara satu sama lain. Jika penjadual benang memperuntukkan masa kepada Thread-1, maka ia serta-merta menulis segala-galanya ke konsol. Perkara lain yang telah atau belum berjaya ditulis tidak penting. Hasilnya, seperti yang anda lihat, sangat menyedihkan. Itulah sebabnya mereka memperkenalkan konsep khas, mutex (mutual exclusion) , kepada pengaturcaraan berbilang benang. Tujuan mutexadalah untuk menyediakan mekanisme supaya hanya satu utas mempunyai akses kepada objek pada masa tertentu. Jika Thread-1 memperoleh mutex objek A, utas lain tidak akan dapat mengakses dan mengubah suai objek tersebut. Benang lain mesti menunggu sehingga muteks objek A dilepaskan. Berikut ialah contoh daripada kehidupan: bayangkan bahawa anda dan 10 orang yang tidak dikenali lain menyertai latihan. Bergilir-gilir, anda perlu menyatakan idea anda dan membincangkan sesuatu. Tetapi kerana anda bertemu untuk kali pertama, untuk tidak mengganggu satu sama lain secara berterusan dan marah, anda menggunakan 'bola bercakap': hanya orang yang memegang bola boleh bercakap. Dengan cara ini anda akhirnya mempunyai perbincangan yang baik dan membuahkan hasil. Pada asasnya, bola adalah mutex. Jika mutex objek berada di tangan satu benang, benang lain tidak boleh berfungsi dengan objek itu.Objectkelas, yang bermaksud bahawa setiap objek di Jawa mempunyai satu.

Cara pengendali yang disegerakkan berfungsi

Mari kenali kata kunci baharu: synchronized . Ia digunakan untuk menandakan blok kod tertentu. Jika blok kod ditandakan dengan synchronizedkata kunci, maka blok itu hanya boleh dilaksanakan oleh satu utas pada satu masa. Penyegerakan boleh dilaksanakan dengan cara yang berbeza. Sebagai contoh, dengan mengisytiharkan keseluruhan kaedah untuk disegerakkan:

public synchronized void doSomething() {

   // ...Method logic
}
Atau tulis blok kod di mana penyegerakan dilakukan menggunakan beberapa objek:

public class Main {

   private Object obj = new Object();

   public void doSomething() {

       // ...Some logic available simultaneously to all threads

       synchronized (obj) {

           // Logic available to just one thread at a time
       }
   }
}
Maksudnya mudah. Jika satu utas masuk ke dalam blok kod yang ditandakan dengan synchronizedkata kunci, ia serta-merta menangkap mutex objek, dan semua utas lain yang cuba memasuki blok atau kaedah yang sama terpaksa menunggu sehingga utas sebelumnya menyelesaikan kerjanya dan melepaskan monitor. Penyegerakan benang.  Pengendali yang disegerakkan - 3By the way! Semasa kursus, anda telah melihat contoh synchronized, tetapi ia kelihatan berbeza:

public void swap()
{
   synchronized (this)
   {
       // ...Method logic
   }
}
Topik ini baru untuk anda. Dan, sudah tentu, akan ada kekeliruan dengan sintaks. Jadi, hafallah dengan segera untuk mengelakkan keliru nanti dengan cara penulisan yang berbeza. Kedua-dua cara menulis 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 thisobjek, iaitu objek semasa. Dan dalam contoh kedua, anda menggunakan synchronizedkata kunci pada keseluruhan kaedah. Ini menjadikannya tidak perlu untuk menunjukkan secara eksplisit objek yang digunakan untuk penyegerakan. Memandangkan keseluruhan kaedah ditandakan dengan kata kunci, kaedah tersebut akan disegerakkan secara automatik untuk semua keadaan kelas. Kami tidak akan menyelami perbincangan tentang cara yang lebih baik. Buat masa ini, pilih mana-mana cara yang paling anda suka :) Perkara utama adalah untuk diingat: anda boleh mengisytiharkan kaedah disegerakkan hanya apabila semua logiknya dilaksanakan oleh satu utas pada satu masa. Sebagai contoh, adalah satu kesilapan untuk membuat doSomething()kaedah berikut disegerakkan:

public class Main {

   private Object obj = new Object();

   public void doSomething() {

       // ...Some logic available simultaneously to all threads

       synchronized (obj) {

           // Logic available to just one thread at a time
       }
   }
}
Seperti yang anda lihat, sebahagian daripada kaedah mengandungi logik yang tidak memerlukan penyegerakan. Kod itu boleh dijalankan oleh berbilang benang pada masa yang sama, dan semua tempat kritikal diasingkan dalam synchronizedblok yang berasingan. Dan satu lagi perkara. Mari kita teliti contoh kita dari pelajaran dengan pertukaran nama:

public void swap()
{
   synchronized (this)
   {
       // ...Method logic
   }
}
Nota: penyegerakan dilakukan menggunakanthis. Iaitu, menggunakanMyClassobjek tertentu. Katakan kita mempunyai 2 utas (Thread-1danThread-2) dan hanya satuMyClass myClassobjek. Dalam kes ini, jikaThread-1memanggilmyClass.swap()kaedah, mutex objek akan sibuk, dan apabila cuba memanggilmyClass.swap()kaedahThread-2akan tergantung sementara menunggu mutex dikeluarkan. Jika kita akan mempunyai 2 utas dan 2MyClassobjek (myClass1danmyClass2), utas kita boleh secara serentak melaksanakan kaedah yang disegerakkan pada objek yang berbeza. Benang pertama melaksanakan ini:

myClass1.swap();
Yang kedua melaksanakan ini:

myClass2.swap();
Dalam kes ini, synchronizedkata kunci dalam swap()kaedah tidak akan menjejaskan pengendalian program, kerana penyegerakan dilakukan menggunakan 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 memperoleh satu adalah bebas daripada memperoleh yang lain .

Ciri khas penyegerakan dalam kaedah statik

Tetapi bagaimana jika anda perlu menyegerakkan kaedah statik ?

class MyClass {
   private static String name1 = "Ally";
   private static String name2 = "Lena";

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

}
Tidak jelas apakah peranan yang akan dimainkan oleh mutex di sini. Lagipun, kami sudah menentukan bahawa setiap objek mempunyai mutex. Tetapi masalahnya ialah kita tidak memerlukan objek untuk memanggil MyClass.swap()kaedah: kaedahnya statik! Jadi apa seterusnya? :/ Sebenarnya tiada masalah di sini. Pencipta Java telah menguruskan segala-galanya :) Jika kaedah yang mengandungi logik serentak kritikal adalah statik, maka penyegerakan dilakukan pada peringkat kelas. Untuk lebih jelas, kita boleh menulis semula kod di atas seperti berikut:

class MyClass {
   private static String name1 = "Ally";
   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: Oleh kerana tiada objek, mekanisme penyegerakan mesti entah bagaimana dimasukkan ke dalam kelas itu sendiri. Dan begitulah keadaannya: kita boleh menggunakan kelas untuk menyegerakkan.
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION