Bagaimana Anda membunuh java.lang.Thread
di Jawa?
ExecutorStatus
pertanyaan ini: stackoverflow.com/questions/2275443/how-to-timeout-a-thread
Bagaimana Anda membunuh java.lang.Thread
di Jawa?
ExecutorStatus
pertanyaan ini: stackoverflow.com/questions/2275443/how-to-timeout-a-thread
Jawaban:
Lihat utasThread.stop()
ini dari Sun tentang mengapa mereka usang . Ini menjelaskan secara rinci mengapa ini adalah metode yang buruk dan apa yang harus dilakukan untuk menghentikan utas secara umum.
Cara yang mereka rekomendasikan adalah menggunakan variabel bersama sebagai bendera yang meminta utas latar untuk berhenti. Variabel ini kemudian dapat diatur oleh objek berbeda yang meminta utas diakhiri.
getConnection()
dari java.sql.DriverManager
. Jika waktu koneksi terlalu lama saya mencoba untuk mematikan utas yang sesuai dengan menelepon Thread.interrupt()
tetapi tidak mempengaruhi utas sama sekali. The Thread.stop()
bekerja Namun, meskipun oracle mengatakan tidak harus bekerja jika interrupt()
tidak. Saya bertanya-tanya bagaimana membuatnya bekerja dan menghindari menggunakan metode yang sudah usang.
Secara umum Anda tidak ..
Anda memintanya untuk menghentikan apa pun yang dilakukannya menggunakan Thread.interrupt () (tautan javadoc)
Penjelasan yang baik tentang mengapa ada di javadoc di sini (tautan technote java)
interrupt()
metode dipanggil? Pertanyaan utama terkait dengan pembuatan log untuk setiap utas baru.
Di Jawa utas tidak terbunuh, tetapi penghentian utas dilakukan dengan cara yang kooperatif . Utas diminta untuk mengakhiri dan utas kemudian dapat ditutup dengan anggun.
Seringkali sebuah volatile boolean
bidang digunakan dimana utas secara berkala memeriksa dan berakhir ketika disetel ke nilai yang sesuai.
Saya tidak akan menggunakan a boolean
untuk memeriksa apakah utasnya harus berakhir . Jika Anda menggunakan volatile
sebagai pengubah bidang, ini akan berfungsi andal, tetapi jika kode Anda menjadi lebih kompleks, karena alih-alih menggunakan metode pemblokiran lain di dalam while
loop, itu mungkin terjadi, bahwa kode Anda tidak akan berhenti sama sekali atau setidaknya membutuhkan waktu lebih lama karena Anda mungkin mau.
Metode perpustakaan pemblokiran tertentu mendukung gangguan.
Setiap utas sudah memiliki status boolean flag interrupt dan Anda harus memanfaatkannya. Itu bisa diimplementasikan seperti ini:
public void run() {
try {
while (!interrupted()) {
// ...
}
} catch (InterruptedException consumed)
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); }
Kode sumber diadaptasi dari Java Concurrency in Practice . Karena cancel()
metode ini bersifat publik, Anda dapat membiarkan utas lain memanggil metode ini seperti yang Anda inginkan.
Salah satu caranya adalah dengan mengatur variabel kelas dan menggunakannya sebagai sentinel.
Class Outer {
public static volatile flag = true;
Outer() {
new Test().start();
}
class Test extends Thread {
public void run() {
while (Outer.flag) {
//do stuff here
}
}
}
}
Tetapkan variabel kelas eksternal, yaitu flag = true pada contoh di atas. Setel ke false untuk 'membunuh' utas.
volatile
untuk memastikan itu berfungsi dengan baik di mana-mana. Kelas dalam tidak statis, jadi flag harus variabel instan. Bendera harus dibersihkan dalam metode accessor sehingga operasi lain (seperti interupsi) dapat dilakukan. Nama "bendera" tidak deskriptif.
Ada cara bagaimana Anda bisa melakukannya. Tetapi jika Anda harus menggunakannya, Anda adalah programmer yang buruk atau Anda menggunakan kode yang ditulis oleh programmer yang buruk. Jadi, Anda harus berpikir tentang berhenti menjadi programmer yang buruk atau berhenti menggunakan kode buruk ini. Solusi ini hanya untuk situasi ketika TIDAK ADA CARA LAIN.
Thread f = <A thread to be stopped>
Method m = Thread.class.getDeclaredMethod( "stop0" , new Class[]{Object.class} );
m.setAccessible( true );
m.invoke( f , new ThreadDeath() );
Thread.stop
bahkan jika sudah usang.
Thread.stop
melakukan hal yang sama tetapi juga memeriksa akses dan izin. Penggunaannya Thread.stop
agak jelas, dan saya tidak ingat alasan mengapa saya menggunakan Thread.stop0
itu. Mungkin Thread.stop
tidak berfungsi untuk kasus khusus saya (Weblogic on Java 6). Atau mungkin karena Thread.stop
sudah usang dan menyebabkan peringatan.
Saya ingin menambahkan beberapa pengamatan, berdasarkan komentar yang telah terkumpul.
Thread.stop()
akan menghentikan utas jika manajer keamanan mengizinkannya.Thread.stop()
berbahaya. Karena itu, jika Anda bekerja di lingkungan JEE dan Anda tidak memiliki kendali atas kode yang dipanggil, mungkin diperlukan; lihat Mengapa Thread.stop ditinggalkan?stop()
membuat ThreadDeathError
kesalahan baru pada utas panggilan dan kemudian melemparkan kesalahan itu pada utas target . Oleh karena itu, jejak tumpukan umumnya tidak berharga.stop()
periksa dengan manajer keamanan dan kemudian panggil panggilan stop1()
itu stop0()
. stop0()
adalah kode asliThread.stop()
belum dihapus (belum), tetapi Thread.stop(Throwable)
sudah dihapus di Java 11. ( milis , JDK-8204243 )Saya akan memilih Thread.stop()
.
Misalnya Anda memiliki operasi yang tahan lama (seperti permintaan jaringan). Seharusnya Anda menunggu tanggapan, tetapi itu bisa memakan waktu dan pengguna menavigasi ke UI lain. Utas tunggu ini sekarang a) tidak berguna b) masalah potensial karena ketika dia akan mendapatkan hasil, itu sama sekali tidak berguna dan dia akan memicu panggilan balik yang dapat menyebabkan sejumlah kesalahan.
Semua itu dan dia bisa melakukan pemrosesan respons yang bisa jadi CPU hebat. Dan Anda, sebagai pengembang, bahkan tidak dapat menghentikannya, karena Anda tidak dapat membuang if (Thread.currentThread().isInterrupted())
baris di semua kode.
Jadi ketidakmampuan untuk dengan paksa menghentikan utas itu aneh.
Thread.stop()
dengan aman. Anda tidak memilih Thread.stop()
, Anda meminta setiap orang yang mengimplementasikan setiap operasi yang mungkin membutuhkan waktu lama untuk membuatnya dibatalkan dengan aman. Dan itu mungkin ide yang bagus, tetapi tidak ada hubungannya dengan penerapan Thread.stop()
sebagai cara untuk meminta aborsi yang aman. Kami sudah punya interrupt
untuk itu.
stop
.
Pertanyaannya agak kabur. Jika Anda bermaksud "bagaimana saya menulis sebuah program sehingga utas berhenti berjalan ketika saya menginginkannya", maka berbagai tanggapan lain harus membantu. Tetapi jika Anda bermaksud "Saya memiliki keadaan darurat dengan server saya tidak dapat memulai kembali sekarang dan saya hanya perlu utas mati, apa pun yang terjadi", maka Anda memerlukan alat intervensi untuk mencocokkan seperti alat pemantauan jstack
.
Untuk tujuan ini saya membuat jkillthread . Lihat instruksi penggunaannya.
Tentu saja ada kasus di mana Anda menjalankan semacam kode yang tidak sepenuhnya tepercaya. (Saya pribadi memiliki ini dengan mengizinkan skrip yang diunggah untuk dieksekusi di lingkungan Java saya. Ya, ada bel alarm keamanan yang berdering di mana-mana, tetapi ini adalah bagian dari aplikasi.) untuk menghormati semacam sinyal boolean run / jangan-lari. Satu-satunya kegagalan yang layak Anda lakukan adalah memanggil metode stop pada utas jika, katakanlah, itu berjalan lebih lama dari batas waktu tertentu.
Tapi, ini hanya "layak", dan tidak absolut, karena kode dapat menangkap kesalahan ThreadDeath (atau pengecualian apa pun yang Anda lemparkan secara eksplisit), dan jangan rethrow seperti yang seharusnya dilakukan oleh thread sopan. Jadi, intinya adalah AFAIA tidak ada kegagalan mutlak yang aman.
Tidak ada cara untuk membunuh thread dengan anggun.
Anda dapat mencoba untuk menghentikan utas, salah satu strategi yang umum adalah menggunakan pil racun untuk mengirim utas untuk menghentikannya
public class CancelSupport {
public static class CommandExecutor implements Runnable {
private BlockingQueue<String> queue;
public static final String POISON_PILL = “stopnow”;
public CommandExecutor(BlockingQueue<String> queue) {
this.queue=queue;
}
@Override
public void run() {
boolean stop=false;
while(!stop) {
try {
String command=queue.take();
if(POISON_PILL.equals(command)) {
stop=true;
} else {
// do command
System.out.println(command);
}
} catch (InterruptedException e) {
stop=true;
}
}
System.out.println(“Stopping execution”);
}
}
}
BlockingQueue<String> queue=new LinkedBlockingQueue<String>();
Thread t=new Thread(new CommandExecutor(queue));
queue.put(“hello”);
queue.put(“world”);
t.start();
Thread.sleep(1000);
queue.put(“stopnow”);
Secara umum Anda tidak membunuh, menghentikan, atau menyela utas (atau memeriksa apakah itu terputus ()), tetapi biarkan itu berakhir secara alami.
Sederhana saja. Anda bisa menggunakan loop apa saja bersama-sama dengan variabel (volatile) boolean di dalam run () metode untuk mengontrol aktivitas utas. Anda juga dapat kembali dari utas aktif ke utas utama untuk menghentikannya.
Dengan cara ini Anda dengan anggun membunuh utas :).
Upaya penghentian utas secara tiba-tiba adalah praktik pemrograman buruk yang terkenal dan bukti desain aplikasi yang buruk. Semua utas dalam aplikasi multithreaded secara eksplisit dan implisit berbagi keadaan proses yang sama dan dipaksa untuk bekerja sama satu sama lain agar tetap konsisten, jika tidak aplikasi Anda akan rentan terhadap bug yang akan sangat sulit untuk didiagnosis. Jadi, merupakan tanggung jawab pengembang untuk memberikan jaminan konsistensi seperti itu melalui desain aplikasi yang cermat dan jelas.
Ada dua solusi tepat utama untuk terminasi thread yang dikendalikan:
Penjelasan yang baik dan terperinci tentang masalah yang terkait dengan penghentian thread mendadak serta contoh solusi yang salah dan tepat untuk penghentian thread terkontrol dapat ditemukan di sini:
Berikut adalah beberapa bacaan yang bagus tentang masalah ini:
Saya tidak mendapatkan interupsi untuk bekerja di Android, jadi saya menggunakan metode ini, bekerja dengan sempurna:
boolean shouldCheckUpdates = true;
private void startupCheckForUpdatesEveryFewSeconds() {
Thread t = new Thread(new CheckUpdates());
t.start();
}
private class CheckUpdates implements Runnable{
public void run() {
while (shouldCheckUpdates){
//Thread sleep 3 seconds
System.out.println("Do your thing here");
}
}
}
public void stop(){
shouldCheckUpdates = false;
}
'Membunuh utas' bukanlah frasa yang tepat untuk digunakan. Berikut ini adalah salah satu cara kami dapat mengimplementasikan penyelesaian / keluar dari utas atas kehendak:
Runnable yang saya gunakan:
class TaskThread implements Runnable {
boolean shouldStop;
public TaskThread(boolean shouldStop) {
this.shouldStop = shouldStop;
}
@Override
public void run() {
System.out.println("Thread has started");
while (!shouldStop) {
// do something
}
System.out.println("Thread has ended");
}
public void stop() {
shouldStop = true;
}
}
Kelas pemicu:
public class ThreadStop {
public static void main(String[] args) {
System.out.println("Start");
// Start the thread
TaskThread task = new TaskThread(false);
Thread t = new Thread(task);
t.start();
// Stop the thread
task.stop();
System.out.println("End");
}
}
Thread.stop sudah usang jadi bagaimana kita menghentikan utas di java?
Selalu gunakan metode interupsi dan masa depan untuk meminta pembatalan
Callable < String > callable = new Callable < String > () {
@Override
public String call() throws Exception {
String result = "";
try {
//assume below take method is blocked as no work is produced.
result = queue.take();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return result;
}
};
Future future = executor.submit(callable);
try {
String result = future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
logger.error("Thread timedout!");
return "";
} finally {
//this will call interrupt on queue which will abort the operation.
//if it completes before time out, it has no side effects
future.cancel(true);
}
public interface CustomCallable < T > extends Callable < T > {
void cancel();
RunnableFuture < T > newTask();
}
public class CustomExecutorPool extends ThreadPoolExecutor {
protected < T > RunnableFuture < T > newTaskFor(Callable < T > callable) {
if (callable instanceof CancellableTask)
return ((CancellableTask < T > ) callable).newTask();
else
return super.newTaskFor(callable);
}
}
public abstract class UnblockingIOTask < T > implements CustomCallable < T > {
public synchronized void cancel() {
try {
obj.close();
} catch (IOException e) {
logger.error("io exception", e);
}
}
public RunnableFuture < T > newTask() {
return new FutureTask < T > (this) {
public boolean cancel(boolean mayInterruptIfRunning) {
try {
this.cancel();
} finally {
return super.cancel(mayInterruptIfRunning);
}
}
};
}
}