Pertanyaan Java threading / volatile


Saya punya utas:

class Foo extends Thread
{
    boolean active = true;

    public void run()
    {
        while(active)
        {
            //do stuff
        }
    }

    public void end()
    {
        active = false;
    }

    public void hibernate()
    {
        synchronized(this)
        {
            wait();
        }
    }
 }

Jika panggilan benang lain end(), akan Foo segera lihat itu active sekarang false? Khususnya, karena active tidak volatileSaya tidak yakin itu akan terjadi. Saya awalnya dibuat end() sebagai cara cerdas untuk menghindari volatil, tetapi sekarang saya tidak yakin itu akan benar-benar melakukan apa yang saya maksud. Selain itu, jika panggilan benang lain hibernate(), thread mana yang akan tidur? Saya berniat Foo untuk tidur, jadi jika ini tidak melakukan apa yang saya inginkan, saran alternatif akan sangat diterima.


5
2017-08-27 02:24


asal


Jawaban:


Jika thread lain memanggil end (), akankah Foo segera melihat bahwa aktif sekarang salah?

Tidak, itu tidak akan terjadi. Atau setidaknya, tidak akan melihatnya sepanjang waktu.

jika kamu mau run untuk selalu melihat nilai baru dengan segera, harus ada hubungan "datang setelah" antara penugasan utas ke variabel dan utas pembacaannya. Ini dapat dicapai:

  • dengan menyatakan active volatile,
  • dengan menaruh synchronized blok di sekitar pernyataan yang membaca dan menulis variabel,
  • dengan membuat variabel sebagai tipe "atom"; misalnya AtomicBoolean, atau
  • dengan menggunakan beberapa kelas konkurensi lain yang sesuai; lihat java.util.concurrent.* paket.

... cara cerdas menghindari volatile ...

Mendeklarasikan variabel menjadi volatile adalah salah satu cara untuk memastikan sinkronisasi yang tepat. Ini adalah fakta bahwa sinkronisasi yang tepat membebani overhead kinerja. Namun, sinkronisasi yang tepat sangat penting agar aplikasi Anda bekerja dengan andal, dan BUKAN "pintar" untuk menghindarinya.

(Tanpa sinkronisasi yang tepat, program Anda mungkin masih akan bekerja hampir sepanjang waktu, dan mungkin akan selalu berfungsi pada beberapa mesin. Namun, terkadang tidak akan berfungsi, dan perilaku yang sebenarnya mungkin bergantung pada mesin apa yang Anda jalankan program pada, apa beban mesin, dan hal lainnya.)

Selain itu, jika thread lain memanggil hibernate (), thread mana yang akan pergi tidur?

Untaian yang membuat panggilan akan tertidur. Dan itu tidak akan bangun kecuali beberapa thread lain melakukan notify atau notifyAll pada objek Foo yang sama.

Jika Anda hanya ingin aplikasi untuk tidur dan bangun sedikit kemudian, gunakan Thread.sleep. Tapi hati-hati menggunakan itu sleep dengan cara yang salah dapat membuat aplikasi Anda lambat dan tidak responsif.


12
2017-08-27 02:35



Kecurigaan Anda benar: karena active tidak volatile, tidak ada jaminan itu run() akan pernah melihat perubahan yang dilakukan pada utas lainnya.

Secara umum, cara-cara "pintar" menghindari volatile hampir selalu merupakan ide yang buruk. Bahkan, bahkan volatile adalah sesuatu yang sebaiknya tidak Anda pilih. Sering kali lebih aman untuk tetap mengunci, memonitor, atau mekanisme sinkronisasi tingkat tinggi.

Untuk pertanyaan kedua Anda, benang yang akan pergi tidur adalah yang dipanggil hibernate(). Benang itu akan tertidur sampai terputus, ia mengalami wakeup palsu, atau beberapa panggilan ulir lainnya notify()/notifyAll() pada Foo monitor instance. Biasanya kesalahan untuk menelepon Object#wait()tanpa mengitarinya dengan loop yang memeriksa kondisi yang sedang menunggu.

Anda juga tampaknya bingung tentang ide a Foo Misalnya "akan tidur". SEBUAH Foo contoh bukan Thread (atau bahkan a Runnable), dan tidak membuat utasnya sendiri, jadi ide untuk tidur tidak masuk akal. Apa yang Anda mungkin coba capai adalah meletakkan panggilan benang Foo#run() tidur.


5
2017-08-27 02:34



Mengenai pertanyaan pertama Anda menghindari volatile, Anda harus mencoba menggunakan Thread interruption untuk menandakan thread yang sedang berjalan untuk berhenti.

Menggunakan mengganggu() metode instance dari utas lain untuk menginterupsi untaian yang berjalan.

Menggunakan isInterrupted () metode di thread Anda yang sedang berjalan untuk memeriksa interupsi.

while(!this.isInterrupted()){
   //do your work here.
}

Tidak yakin mengapa Anda ingin memperpanjang kelas Thread. Jika Anda mengimplementasikan Runnable dalam hal ini, Anda harus menggunakan terputus dalam metode lari Anda untuk memeriksa interupsi. Silakan baca javadocs untuk mengetahui tentang beberapa peringatan dari metode ini.


0
2017-08-27 04:44