JavaRush /Java Blog /Random-ID /Sinkronisasi utas. Operator tersinkronisasi di Java

Sinkronisasi utas. Operator tersinkronisasi di Java

Dipublikasikan di grup Random-ID
Halo! Hari ini kami akan terus mempertimbangkan fitur pemrograman multi-thread dan berbicara tentang sinkronisasi thread.
Sinkronisasi utas.  Operator disinkronkan - 1
Apa itu "sinkronisasi"? Di luar bidang pemrograman, ini mengacu pada semacam pengaturan yang memungkinkan dua perangkat atau program untuk bekerja sama. Misalnya, ponsel cerdas dan komputer dapat disinkronkan dengan akun Google, dan akun pribadi di situs web dapat disinkronkan dengan akun di jejaring sosial untuk login menggunakannya. Sinkronisasi thread memiliki arti serupa: mengatur bagaimana thread berinteraksi satu sama lain. Dalam kuliah sebelumnya, thread kami hidup dan bekerja secara terpisah satu sama lain. Yang satu sedang menghitung sesuatu, yang kedua sedang tidur, yang ketiga sedang menampilkan sesuatu di konsol, tetapi mereka tidak berinteraksi satu sama lain. Dalam program nyata situasi seperti ini jarang terjadi. Beberapa thread dapat bekerja secara aktif, misalnya, dengan kumpulan data yang sama dan mengubah sesuatu di dalamnya. Hal ini menimbulkan masalah. Bayangkan beberapa thread menulis teks ke lokasi yang sama, seperti file teks atau konsol. File atau konsol ini dalam hal ini menjadi sumber daya bersama. Thread tidak mengetahui keberadaan satu sama lain, sehingga thread hanya menuliskan segala sesuatu yang dapat mereka kelola dalam waktu yang dialokasikan oleh penjadwal thread. Dalam kuliah kursus baru-baru ini, kita punya contoh tentang apa yang akan terjadi, mari kita ingat: Sinkronisasi utas.  Operator tersinkronisasi - 2Alasannya terletak pada kenyataan bahwa thread bekerja dengan sumber daya bersama, konsol, tanpa mengoordinasikan tindakan satu sama lain. Jika penjadwal thread telah mengalokasikan waktu untuk Thread-1, ia akan segera menulis semuanya ke konsol. Apa yang sudah atau belum berhasil ditulis oleh thread lain tidaklah penting. Hasilnya, seperti yang Anda lihat, adalah bencana. Oleh karena itu, dalam pemrograman multi-thread, konsep khusus mutex diperkenalkan (dari bahasa Inggris "mutex", "mutualclusion" - "mutualclusion") . Tujuan dari mutex adalah untuk menyediakan mekanisme sehingga hanya satu thread yang memiliki akses ke suatu objek pada waktu tertentu. Jika Thread-1 telah memperoleh mutex objek A, thread lain tidak akan memiliki akses ke mutex tersebut untuk mengubah apa pun di dalamnya. Hingga mutex objek A dilepaskan, thread yang tersisa akan terpaksa menunggu. Contoh kehidupan nyata: bayangkan Anda dan 10 orang asing lainnya berpartisipasi dalam sebuah pelatihan. Anda perlu bergantian mengungkapkan ide dan mendiskusikan sesuatu. Namun, karena Anda baru pertama kali bertemu, agar tidak terus-menerus menyela dan tidak terlibat dalam keriuhan, Anda menggunakan aturan "bola berbicara": hanya satu orang yang dapat berbicara - orang yang menguasai bola tangannya. Dengan cara ini diskusi menjadi memadai dan bermanfaat. Jadi, mutex, pada dasarnya, adalah sebuah bola. Jika mutex suatu objek berada di tangan satu thread, thread lain tidak akan dapat mengakses objek tersebut. Anda tidak perlu melakukan apa pun untuk membuat mutex: mutex sudah ada di dalam kelas Object, yang berarti setiap objek di Java memilikinya.

Cara kerja operator tersinkronisasi di Java

Mari berkenalan dengan kata kunci baru - tersinkronisasi . Itu menandai bagian tertentu dari kode kita. Jika sebuah blok kode ditandai dengan kata kunci tersinkronisasi, itu berarti blok tersebut hanya dapat dieksekusi oleh satu thread dalam satu waktu. Sinkronisasi dapat diterapkan dengan berbagai cara. Misalnya, buat seluruh metode tersinkronisasi:
public synchronized void doSomething() {

   //...method logic
}
Atau tulis blok kode tempat sinkronisasi dilakukan 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
       }
   }
}
Artinya sederhana. Jika satu thread memasukkan blok kode yang ditandai dengan kata disinkronkan, maka thread tersebut langsung memperoleh mutex objek, dan semua thread lain yang mencoba memasukkan blok atau metode yang sama terpaksa menunggu hingga thread sebelumnya menyelesaikan pekerjaannya dan melepaskan blok kode tersebut. memantau. Sinkronisasi utas.  Operator tersinkronisasi - 3Omong-omong! Dalam perkuliahan, Anda telah melihat contoh sinkronisasi, tetapi tampilannya berbeda:
public void swap()
{
   synchronized (this)
   {
       //...method logic
   }
}
Topiknya baru bagi Anda, dan tentu saja akan ada kebingungan dengan sintaksisnya pada awalnya. Oleh karena itu, segera ingat agar tidak bingung nantinya dalam cara penulisannya. Kedua metode penulisan ini memiliki arti yang sama:
public void swap() {

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


public synchronized void swap() {

   }
}
Dalam kasus pertama, Anda membuat blok kode yang disinkronkan segera setelah memasukkan metode tersebut. Itu disinkronkan oleh object this, yaitu oleh objek saat ini. Dan pada contoh kedua Anda memasukkan kata sinkronisasi pada seluruh metode. Tidak ada lagi kebutuhan untuk secara eksplisit menunjukkan objek apa pun yang sinkronisasinya dilakukan. Setelah seluruh metode ditandai dengan sebuah kata, metode ini akan secara otomatis disinkronkan untuk semua objek kelas. Mari kita tidak membahas lebih dalam tentang metode mana yang lebih baik. Untuk saat ini, pilih yang paling Anda sukai :) Hal utama yang perlu diingat: Anda dapat mendeklarasikan metode yang disinkronkan hanya jika semua logika di dalamnya dijalankan oleh satu thread pada saat yang bersamaan. Misalnya, dalam hal ini doSomething()akan terjadi kesalahan saat membuat metode disinkronkan:
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, sebagian metode berisi logika yang tidak memerlukan sinkronisasi. Kode di dalamnya dapat dieksekusi oleh beberapa thread secara bersamaan, dan semua tempat penting dialokasikan ke blok tersinkronisasi terpisah. Dan suatu saat. Mari kita lihat di bawah mikroskop contoh kuliah kita dengan pertukaran nama:
public void swap()
{
   synchronized (this)
   {
       //...method logic
   }
}
Harap diperhatikan: sinkronisasi dilakukan menggunakan this. Artinya, untuk objek tertentu MyClass. Bayangkan kita mempunyai 2 thread ( Thread-1dan Thread-2) dan hanya satu objek MyClass myClass. Dalam hal ini, jika Thread-1metode dipanggil myClass.swap(), mutex objek akan sibuk, dan Thread-2ketika Anda mencoba memanggilnya, myClass.swap()mutex akan hang menunggu mutex menjadi bebas. Jika kita memiliki 2 thread dan 2 objek MyClass- myClass1dan myClass2- pada objek yang berbeda, thread kita dapat dengan mudah menjalankan metode tersinkronisasi secara bersamaan. Thread pertama melakukan:
myClass1.swap();
Yang kedua melakukan:
myClass2.swap();
Dalam hal ini, kata kunci sinkronisasi di dalam metode swap()tidak akan mempengaruhi pengoperasian program, karena sinkronisasi dilakukan pada objek tertentu. Dan dalam kasus terakhir, kita memiliki 2 objek, sehingga thread tidak menimbulkan masalah satu sama lain. Lagi pula, dua objek memiliki 2 mutex yang berbeda, dan penangkapannya tidak bergantung satu sama lain.

Fitur sinkronisasi dalam metode statis

Namun bagaimana jika Anda perlu menyinkronkan metode statis?
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 menjadi mutex dalam kasus ini. Bagaimanapun, kita telah memutuskan bahwa setiap objek memiliki mutex. Namun masalahnya adalah untuk memanggil metode statis MyClass.swap()kita tidak memerlukan objek: metode tersebut statis! Jadi, apa selanjutnya? :/ Sebenarnya tidak ada masalah dengan ini. Pembuat Java mengurus semuanya :) Jika metode yang berisi logika kritis "multithread" bersifat statis, sinkronisasi akan dilakukan berdasarkan kelas. Untuk lebih jelasnya, kode di atas dapat ditulis ulang menjadi:
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 prinsipnya, Anda dapat memikirkan hal ini sendiri: karena tidak ada objek, maka mekanisme sinkronisasi harus “tertanam” ke dalam kelas itu sendiri. Begitulah caranya: Anda juga dapat melakukan sinkronisasi antar kelas.
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION