Kode berikut mengarah ke java.lang.IllegalThreadStateException: Thread already started
ketika saya memanggil start()
metode kedua kalinya dalam program.
updateUI.join();
if (!updateUI.isAlive())
updateUI.start();
Ini terjadi untuk kedua kalinya updateUI.start()
dipanggil. Saya telah melewatinya beberapa kali dan utas dipanggil dan selesai berjalan sampai selesai sebelum memukul updateUI.start()
.
Memanggil updateUI.run()
menghindari kesalahan tetapi menyebabkan utas berjalan di utas UI (utas pemanggil, seperti yang disebutkan dalam posting lain di SO), yang bukan itu yang saya inginkan.
Bisakah sebuah Thread dimulai hanya sekali? Jika ya, apa yang harus saya lakukan jika saya ingin menjalankan utas lagi? Utas khusus ini melakukan beberapa kalkulasi di latar belakang, jika saya tidak melakukannya di utas daripada yang dilakukan di utas UI dan pengguna harus menunggu terlalu lama.
sumber
Jawaban:
Dari Spesifikasi Java API untuk
Thread.start
metode:Selanjutnya:
Jadi ya, a
Thread
hanya bisa dimulai sekali.Jika a
Thread
perlu dijalankan lebih dari sekali, maka seseorang harus membuat instance baru dariThread
dan memanggilnyastart
.sumber
Thread
setiap kali. Sebaliknya, itu harus mengirimkan tugas ke kumpulan benang (misalnya,java.util.concurrent.ThreadPoolExecutor
)Benar sekali. Dari dokumentasi :
Dalam hal apa yang dapat Anda lakukan untuk komputasi berulang, sepertinya Anda dapat menggunakan metode invokeLater SwingUtilities . Anda sudah bereksperimen dengan menelepon
run()
secara langsung, artinya Anda sudah berpikir untuk menggunakan aRunnable
daripada mentahThread
. Coba gunakaninvokeLater
metode ini hanya padaRunnable
tugas dan lihat apakah itu sesuai dengan pola mental Anda.Berikut contoh dari dokumentasinya:
Runnable doHelloWorld = new Runnable() { public void run() { // Put your UI update computations in here. // BTW - remember to restrict Swing calls to the AWT Event thread. System.out.println("Hello World on " + Thread.currentThread()); } }; SwingUtilities.invokeLater(doHelloWorld); System.out.println("This might well be displayed before the other message.");
Jika Anda mengganti
println
panggilan itu dengan komputasi Anda, mungkin itu yang Anda butuhkan.EDIT: menindaklanjuti komentar, saya tidak melihat tag Android di postingan asli. Setara dengan invokeLater di pekerjaan Android adalah
Handler.post(Runnable)
. Dari javadocnya:/** * Causes the Runnable r to be added to the message queue. * The runnable will be run on the thread to which this handler is * attached. * * @param r The Runnable that will be executed. * * @return Returns true if the Runnable was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */
Jadi, di dunia Android, Anda dapat menggunakan contoh yang sama seperti di atas, mengganti
Swingutilities.invokeLater
dengan postingan yang sesuai menjadi fileHandler
.sumber
RunOnUIThread(Runnable)
atauView.post(Runnable)
alih-alih membuat Handler Anda sendiri. Ini akan menjalankan runnable pada utas utama yang memungkinkan Anda memperbarui UI.Jawaban yang baru saja tiba mencakup mengapa Anda tidak boleh melakukan apa yang Anda lakukan. Berikut beberapa opsi untuk menyelesaikan masalah Anda yang sebenarnya.
Buang utas Anda sendiri dan gunakan
AsyncTask
.Atau buat utas baru saat Anda membutuhkannya.
Atau atur utas Anda agar beroperasi di luar antrean kerja (misalnya,
LinkedBlockingQueue
) daripada memulai ulang utas.sumber
Tidak , kita tidak bisa memulai Thread lagi, hal itu akan memunculkan runtimeException java.lang.IllegalThreadStateException. >
Mari kita ambil contoh- Berpikir untuk memulai utas lagi dan memanggil metode start () di atasnya (yang secara internal akan memanggil metode run ()) bagi kita adalah beberapa hal seperti meminta orang mati untuk bangun dan lari. Seperti, setelah menyelesaikan hidupnya orang pergi ke keadaan mati.
public class MyClass implements Runnable{ @Override public void run() { System.out.println("in run() method, method completed."); } public static void main(String[] args) { MyClass obj=new MyClass(); Thread thread1=new Thread(obj,"Thread-1"); thread1.start(); thread1.start(); //will throw java.lang.IllegalThreadStateException at runtime } }
Periksa ini
sumber
Yang harus Anda lakukan adalah membuat Runnable dan membungkusnya dengan Thread baru setiap kali Anda ingin menjalankan Runnable. Ini akan sangat buruk untuk dilakukan tetapi Anda dapat membungkus utas dengan utas lain untuk menjalankan kode untuk itu lagi tetapi hanya melakukan ini adalah Anda benar-benar harus melakukannya.
sumber
Seperti yang Anda katakan, utas tidak dapat dimulai lebih dari sekali.
Langsung dari mulut kuda: Spesifikasi API Java
Jika Anda perlu menjalankan ulang apa pun yang terjadi di utas Anda, Anda harus membuat utas baru dan menjalankannya.
sumber
Untuk menggunakan kembali thread adalah tindakan ilegal di Java API. Namun, Anda dapat menggabungkannya menjadi implementasi yang dapat dijalankan dan menjalankan ulang instance itu lagi.
sumber
Ya, kami tidak dapat mulai menjalankan utas. Ini akan memunculkan IllegalThreadStateException saat runtime - jika utas sudah dimulai.
Bagaimana jika Anda benar-benar perlu memulai utas: Opsi 1) Jika utas perlu dijalankan lebih dari sekali, maka seseorang harus membuat contoh baru dari utas dan memanggilnya mulai.
sumber
Iya. Anda bisa memulainya tepat sekali.
Jangan lari
Thread
lagi. Sebagai gantinya buat Runnable dan posting di Handler of HandlerThread . Anda dapat mengirimkan banyakRunnable
objek. Jika ingin mengirim data kembali ke UI Thread, dengan-inRunnable
run()
metode Anda , postingMessage
diHandler
UI Thread dan proseshandleMessage
Lihat posting ini untuk contoh kode:
Android: Bersulang di utas
sumber
Saya tidak tahu apakah ini praktik yang baik tetapi ketika saya membiarkan run () dipanggil di dalam metode run (), itu tidak menimbulkan kesalahan dan benar-benar melakukan apa yang saya inginkan.
Saya tahu ini tidak memulai utas lagi, tetapi mungkin ini berguna untuk Anda.
public void run() { LifeCycleComponent lifeCycleComponent = new LifeCycleComponent(); try { NetworkState firstState = lifeCycleComponent.getCurrentNetworkState(); Thread.sleep(5000); if (firstState != lifeCycleComponent.getCurrentNetworkState()) { System.out.println("{There was a NetworkState change!}"); run(); } else { run(); } } catch (SocketException | InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { Thread checkingNetworkStates = new Thread(new LifeCycleComponent()); checkingNetworkStates.start(); }
Semoga ini bisa membantu, meski hanya sedikit.
Bersulang
sumber
Saya harus memperbaiki kebocoran sumber daya yang disebabkan oleh pemrogram yang membuat Thread tetapi alih-alih memulai (), dia memanggil metode run () - secara langsung. Jadi hindarilah, kecuali Anda benar-benar tahu apa efek samping yang ditimbulkannya.
sumber
run()
secara langsung, hanya untuk menyematkan Runnable di Thread dan mungkin dipanggilstart()
.