Bagaimana menghindari sibuk berputar di Jawa

Saya memiliki aplikasi multi-utas di mana sebuah utas mengirim pesan ke utas lain. Thread yang menunggu melakukan polling untuk pesan tersebut dan bereaksi (penguncian ditangani). Seperti ini:

Kode thread tunggu:

while(true)
{
  if(helloArrived())
    System.out.println("Got hello");
  if(byeArrived())
    System.out.println("Got bye");
  if(stopArrived())
    break;
}

Saya ingin menghindari teknik memonopoli cpu ini dan menggunakan sesuatu yang lain sebagai gantinya. Ada ide?

Sunting: Kode sebenarnya ada di bawah:

BlockingQueue<Mail> killMeMailbox = new LinkedBlockingQueue<Mail>();
BlockingQueue<Mail> messageMailbox = new LinkedBlockingQueue<Mail>();

public void run()
    {
        while(true)
        {
            if(killMeMailbox.size() > 0)
            {
                break;
            }
            if(messageMailbox.size() > 0)
            {
              System.out.println(messageMailbox.poll());
            }
        }
     }

public void receiveMail(Mail mail)
    {
        //kill
        if(mail.from == -1)
        {
            killMeMailbox.add(0);
        }
        else
        {
            //other
            try
            {
                messageMailbox.put(mail);
            }
            catch(Exception e)
            {
                System.out.println(e.getMessage());
            }
        }
    }

person Josh    schedule 24.10.2014    source sumber


Jawaban (4)


Cara yang benar untuk menghindari hal ini adalah dengan menggunakan mekanisme tunggu/beritahu yang diterapkan oleh java.lang.Object, atau salah satu mekanisme konkurensi tingkat lebih tinggi yang disediakan oleh perpustakaan kelas Java:

(Pilih mekanisme yang paling cocok dengan kasus penggunaan spesifik Anda ...)


Menggunakan Thread.sleep bukanlah solusi yang baik. Meskipun Anda mengurangi beban CPU (dibandingkan dengan polling loop), sisi sebaliknya adalah Anda mengurangi daya tanggap.


Saya menggunakan BlockingQueue sekarang. Tapi mungkin saya salah melakukannya. Saya baru saja menambahkan kode sebenarnya di atas. Apakah Anda melihat masalah saya?

Ya. Anda menggunakan antrean dengan cara yang dirancang untuk menghindari pemblokiran. Itu pendekatan yang salah. Anda harus menggunakan take() (yang akan memblokir hingga entri tersedia) alih-alih poll(), dan membuang kode yang menguji ukuran antrian.

Barang "killMeMailbox" Anda tampaknya dirancang untuk memungkinkan Anda berhenti menunggu email. Anda seharusnya bisa mengimplementasikannya menggunakan Thread.interrupt. (Interupsi akan membuka blokir panggilan take() ...)

person Stephen C    schedule 24.10.2014
comment
Saya sarankan menyebutkan LockSupport daripada menunggu/beritahu. Ini adalah pengganti 1-untuk-1 untuk menunggu/memberitahukan, tetapi tidak mengalami kondisi balapan. - person Marko Topolnik; 24.10.2014
comment
Saya menggunakan BlockingQueue sekarang. Tapi mungkin saya salah melakukannya. Saya baru saja menambahkan kode sebenarnya di atas. Apakah Anda melihat masalah saya? - person Josh; 24.10.2014
comment
@MarkoTopolnik - Saya mendengar apa yang Anda katakan, tetapi saya tidak memahaminya. Bolehkah saya menyarankan Anda menambahkan jawaban Anda sendiri yang menjelaskan cara menggunakannya. - person Stephen C; 24.10.2014
comment
Sempurna! Take() adalah apa yang saya lewatkan. Terima kasih! - person Josh; 24.10.2014
comment
Lagipula mekanisme itu terlalu rendah sehingga tidak ada gunanya menulis jawaban lengkap di sini hanya untuk itu. Namun karena wait/notify sudah tidak digunakan lagi (istilahnya tidak disarankan), saya tidak akan menyebutkannya. - person Marko Topolnik; 24.10.2014

Anda sedang sibuk menunggu. Anda tidak boleh melakukan itu karena itu membuang-buang siklus CPU. Thread atau proses yang menunggu suatu peristiwa harus berada dalam keadaan diblokir. Berikut adalah cara yang mungkin untuk mencapai hal ini:

person ChrisJ    schedule 24.10.2014

Jika Anda dapat merumuskan kembali masalah Anda dalam kaitannya dengan pelaksana tugas, maka pertimbangkan untuk menggunakan SingleThreadExecutor. Jika Anda memerlukan sesuatu yang lebih eksotis - antrian bersamaan atau bahkan wait()/notify() .

person bobah    schedule 24.10.2014

Sudahkah Anda mencoba memasang Thread.sleep untuk menghindari eksekusi loop while terus-menerus? Ini akan membebaskan CPU untuk thread Anda yang lain dan menghindari babi

http://docs.Oracle.com/javase/tutorial/essential/concurrency/sleep.html

person vicsana1    schedule 24.10.2014
comment
Meskipun penggunaan sleep mungkin berhasil pada beberapa kasus, penggunaan notifyAll()/wait() lebih baik karena alasan daya tanggap. - person Victor Sorokin; 24.10.2014
comment
Kemudian luangkan waktu sebentar untuk tidur atau gunakan struktur data lain. Saya rasa ada beberapa struktur seperti BlockingQueue yang memungkinkan thread menunggu hingga ada sesuatu dalam antrian - person vicsana1; 24.10.2014