Pertanyaan Kapan tepatnya Anda menggunakan kata kunci volatile di Java?


Saya telah membaca "Kapan menggunakan 'volatile' di Java?"Tapi aku masih bingung. Bagaimana saya tahu kapan saya harus menandai variabel volatile? Bagaimana jika saya salah, baik menghilangkan volatile pada sesuatu yang membutuhkan atau menempatkan volatile pada sesuatu yang tidak? Apa aturannya? Ketika Anda mencari tahu variabel apa yang harus mudah berubah dalam kode multithread?


76
2017-08-15 18:36


asal


Jawaban:


Anda pada dasarnya menggunakannya ketika Anda ingin membiarkan variabel anggota diakses oleh beberapa utas tetapi tidak perlu atomicity gabungan (tidak yakin apakah ini adalah terminologi yang benar).

class BadExample {
    private volatile int counter;

    public void hit(){
        /* This operation is in fact two operations:
         * 1) int tmp = this.counter;
         * 2) this.counter = tmp + 1;
         * and is thus broken (counter becomes fewer
         * than the accurate amount).
         */
        counter++;
    }
}

di atas adalah contoh yang buruk, karena Anda perlu atomicity senyawa.

 class BadExampleFixed {
    private int counter;

    public synchronized void hit(){
        /*
         * Only one thread performs action (1), (2) at a time
         * "atomically", in the sense that other threads can not 
         * observe the intermediate state between (1) and (2).
         * Therefore, the counter will be accurate.
         */
        counter++;
    }
}

Sekarang ke contoh yang valid:

 class GoodExample {
    private static volatile int temperature;

    //Called by some other thread than main
    public static void todaysTemperature(int temp){
        // This operation is a single operation, so you 
        // do not need compound atomicity
        temperature = temp;
    }

    public static void main(String[] args) throws Exception{
        while(true){
           Thread.sleep(2000);
           System.out.println("Today's temperature is "+temperature);
        }
    }
}

Sekarang, mengapa tidak bisa Anda gunakan saja private static int temperature? Bahkan Anda dapat (dalam arti bahwa program Anda tidak akan meledak atau sesuatu), tetapi perubahan menjadi temperature oleh utas lainnya mungkin atau mungkin tidak "terlihat" ke utas utama.

Pada dasarnya ini berarti bahwa bahkan mungkin aplikasi Anda. terus menulis Today's temperature is 0 selamanya jika kamu tidak menggunakan volatile (dalam prakteknya, nilai cenderung menjadi akhirnya terlihat. Namun, Anda tidak boleh mengambil risiko tidak menggunakan volatile bila diperlukan, karena dapat menyebabkan bug jahat (yang disebabkan oleh objek yang dibangun secara lengkap, dll.).

Jika Anda meletakkan volatile kata kunci pada sesuatu yang tidak perlu volatile, itu tidak akan mempengaruhi kebenaran kode Anda (yaitu perilaku tidak akan berubah). Dalam hal kinerja, itu akan tergantung pada implementasi JVM. Secara teori Anda mungkin mendapatkan degradasi kinerja kecil karena compiler tidak dapat melakukan pengubahan urutan optimisasi, harus membatalkan cache CPU dll, tetapi sekali lagi kompilator dapat membuktikan bahwa bidang Anda tidak pernah dapat diakses oleh beberapa utas dan menghapus efek dari volatile kata kunci sepenuhnya dan kompilasi ke instruksi yang sama.

EDIT:
Tanggapan untuk komentar ini:

Ok, tetapi mengapa kita tidak bisa membuat todaysTemperature disinkronkan dan membuat pengambil suhu yang disinkronkan?

Anda bisa dan itu akan berperilaku dengan benar. Apa pun yang Anda bisa dengan volatile dapat dilakukan dengan synchronized, tapi tidak sebaliknya. Ada dua alasan yang mungkin Anda sukai volatile jika kamu bisa:

  1. Lebih sedikit bug rawan: Ini tergantung pada konteksnya, tetapi dalam banyak kasus menggunakan volatile kurang rentan terhadap bug konkurensi, seperti memblokir sambil menahan kunci, kebuntuan, dll.
  2. Lebih berkinerja: Dalam sebagian besar implementasi JVM, volatile dapat memiliki throughput yang lebih tinggi dan latensi yang lebih baik. Namun dalam banyak aplikasi perbedaannya terlalu kecil untuk masalah.

94
2017-08-15 18:56



Volatile paling berguna dalam algoritma bebas-lock. Anda menandai variabel yang menyimpan data bersama sebagai volatile ketika Anda tidak menggunakan penguncian untuk mengakses variabel itu dan Anda ingin perubahan yang dibuat oleh satu utas terlihat di yang lain, atau Anda ingin membuat relasi "kebetulan-setelah" untuk memastikan bahwa perhitungan adalah tidak diurutkan ulang, sekali lagi, untuk memastikan perubahan menjadi terlihat pada waktu yang tepat.

Itu JMM Cookbook menjelaskan operasi mana yang dapat dipesan ulang dan mana yang tidak bisa.


14
2017-08-15 18:38



Itu volatile juga dapat digunakan untuk mempublikasikan benda yang tidak berubah dalam Lingkungan multi-berulir.

Mendeklarasikan bidang seperti public volatile ImmutableObject foo mengamankan bahwa semua utas selalu melihat referensi instance yang tersedia saat ini.

Lihat Java Concurrency in Practice untuk lebih lanjut tentang topik itu.


5
2017-08-15 19:12



volatile  kata kunci menjamin bahwa nilai dari variabel volatil akan selalu dibaca dari memori utama dan bukan dari cache lokal Thread.

Dari konkurensi java tutorial  :

Menggunakan variabel volatile mengurangi risiko kesalahan konsistensi memori, karena setiap menulis ke variabel volatile menetapkan hubungan terjadi sebelum dengan pembacaan selanjutnya dari variabel yang sama

Ini berarti bahwa perubahan pada variabel volatil selalu terlihat pada utas lainnya. Ini juga berarti bahwa ketika sebuah thread membaca variabel volatile, ia tidak hanya melihat perubahan terbaru terhadap volatile, tetapi juga efek samping dari kode yang menyebabkan perubahan.

Mengenai kueri Anda:

Bagaimana saya tahu kapan saya harus menandai variabel volatile? Apa aturan praktis ketika mencari tahu variabel apa yang harus mudah berubah dalam kode multithread?

Jika Anda merasa bahwa semua utas pembaca selalu mendapatkan nilai terbaru dari variabel, Anda harus menandai variabel sebagai volatile

Jika Anda memiliki satu penulis utas untuk mengubah nilai dari variabel dan beberapa utas pembaca untuk membaca nilai variabel, pengubah volatil menjamin konsistensi memori.

Jika Anda memiliki beberapa utas untuk menulis dan membaca variabel, volatile pengubah saja tidak menjamin konsistensi memori. Kamu harus synchronize kode atau gunakan tingkat tinggi konkurensi konstruksi seperti Locks, Concurrent Collections, Atomic variables dll.

Pertanyaan / artikel SE terkait:

Penjelasan variabel volatil dalam dokumen Java

Perbedaan antara mudah menguap dan disinkronkan di Jawa

javarevisited artikel


4
2017-09-05 16:43



Sebenarnya tidak setuju dengan contoh yang diberikan di bagian atas memilih jawaban, sepengetahuan saya hal itu TIDAK benar menggambarkan semantik volatil sesuai model memori Java. Volatile memiliki cara semantik yang lebih kompleks.

Dalam contoh yang disediakan, utas utama dapat melanjutkan untuk mencetak "Suhu hari ini adalah 0" selamanya bahkan jika ada alur lain yang seharusnya memperbarui suhu jika thread lain tidak pernah dijadwalkan.

Cara yang lebih baik untuk mengilustrasikan semantik berfluktuasi adalah dengan 2 variabel.

Demi kesederhanaan, kami akan menganggap bahwa satu-satunya cara untuk memperbarui dua variabel adalah melalui metode "setTemperatures".

Demi kesederhanaan, kami akan menganggap bahwa hanya 2 utas yang sedang berjalan, utas utama dan utas 2.

//volatile variable
private static volatile int temperature; 
//any other variable, could be volatile or not volatile doesnt matter.
private static int yesterdaysTemperature
//Called by other thread(s)
public static void setTemperatures(int temp, int yestemp){
    //thread updates yesterday's temperature
    yesterdaysTemperature = yestemp;
    //thread updates today's temperature. 
    //This instruction can NOT be moved above the previous instruction for optimization.
    temperature = temp;
   }

dua instruksi penugasan terakhir bisa TIDAK ditata ulang untuk tujuan optimasi baik oleh compiler, runtime atau perangkat keras.

public static void main(String[] args) throws Exception{
    while(true){
       Thread.sleep(2000);
       System.out.println("Today's temperature is "+temperature); 
       System.out.println("Yesterday's temperature was "+yesterdaysTemperature );
 }
}

Setelah utas utama membaca suhu variabel volatil (dalam proses mencetaknya),

1) Ada jaminan bahwa ia akan melihat paling baru ditulis nilai variabel volatil ini terlepas dari berapa banyak untaian yang ditulis, terlepas dari metode mana mereka memperbaruinya, tersinkronisasi atau tidak.

2) Jika pernyataan system.out di utas utama berjalan, setelah saat instan di mana benang 2 menjalankan pernyataan suhu = temp, baik suhu kemarin dan suhu hari ini akan dijamin untuk mencetak nilai yang ditetapkan di dalamnya oleh utas 2 ketika menjalankan pernyataan suhu = temp.

Situasi ini mendapat LOT lebih kompleks jika a) Beberapa utas berjalan dan b) Ada metode lain selain hanya metode setTemperatures yang dapat memperbarui variabel suhu kemarin dan suhu saat ini yang secara aktif dipanggil oleh utas lainnya. Saya pikir itu akan mengambil ukuran artikel yang layak untuk menganalisis implikasi berdasarkan pada bagaimana Java Memory Model menggambarkan semantik berfluktuasi.

Singkatnya, mencoba untuk hanya menggunakan volatilitas untuk sinkronisasi sangat berisiko, dan Anda akan lebih baik menempel pada sinkronisasi metode Anda.


3
2018-01-14 16:39



http://mindprod.com/jgloss/volatile.html

"Kata kunci volatil digunakan pada variabel yang dapat dimodifikasi secara bersamaan oleh utas lainnya."

"Karena benang lain tidak dapat melihat variabel lokal, tidak pernah ada kebutuhan untuk menandai variabel lokal yang mudah menguap. Anda perlu disinkronkan untuk mengoordinasikan perubahan variabel dari untaian yang berbeda, tetapi sering kali tidak stabil akan melakukan hanya untuk melihatnya."


2
2017-08-15 18:38



voltalie Berarti Terus mengubah nilai.Nilai dari variabel ini tidak akan pernah di-cache secara lokal: semua membaca dan menulis akan langsung menuju "memori utama". Dengan kata lain Java compiler dan Thread yang tidak menyimpan nilai dari variabel ini dan selalu membaca dari memori utama.


2
2018-04-11 05:29