Bagaimana Anda membunuh Utas di Jawa?


374

Bagaimana Anda membunuh java.lang.Threaddi Jawa?


2
sampai sekarang Anda tidak dapat membunuh utas; karena destroy () tidak pernah diimplementasikan karena rawan dead-lock
AZ_

1
Saya lebih suka jawaban mengenai ExecutorStatuspertanyaan ini: stackoverflow.com/questions/2275443/how-to-timeout-a-thread
Kirby

9
@loungerdork "Saya pikir Java harus menerapkan metode berhenti / hancurkan yang aman untuk utas pelarian yang tidak dapat Anda kendalikan, meskipun ada peringatan kehilangan kunci dan perangkap lainnya" Jadi, Anda ingin penghentian utas yang tidak aman . Saya pikir Anda sudah memilikinya.
DJClayworth

4
Sungguh menakjubkan pertanyaan macam apa yang akan mendapatkan 212 suara naik pada tahun 2009. Ini akan segera dihancurkan hari ini.
Jonathon Reinhart

7
@ JonathonReinhart: Kenapa begitu? Tampaknya menjadi pertanyaan yang sah, bahkan akhir-akhir ini. Mungkin Anda tidak tahu frustrasi yang ditimbulkannya ketika Anda memiliki utas pelarian dan hanya dapat menggunakan fungsi yang sudah usang untuk menangani ini entah bagaimana?
TFuto

Jawaban:


189

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.


1
jika Anda memeriksa utas yang telah Anda interupsi isAlive () itu akan mengembalikan Anda benar dan mereka akan terus menambahkan ke ThreadGroup Anda saat ini [], Anda dapat melihat ini menggunakan Thread.currentThread.getThreadGroup (). list (); itu akan mencetak semua utas yang dimilikinya dan Anda akan melihat beberapa contoh utas Anda jika Anda mengulangi alur Anda.
AZ_

3
Jika Anda menggunakan PC maka tidak ada masalah tetapi jika Anda sedang mengembangkan perangkat lunak untuk ponsel (android saya sudah mengalaminya) maka Anda akan mendapatkan OutOfMemoryError
AZ_

2
Dapat / harus dicatat, bahwa untuk memastikan komunikasi yang cepat dari stop-request melalui flag, variabel harus volatile (atau akses ke variabel harus disinkronkan), sebagaimana dinyatakan dalam rekomendasi.
mtsz

2
Tautan itu telah terbunuh pada saat ini. Saya dapat menemukannya di archive.org, meskipun: web.archive.org/web/20090202093154/http://java.sun.com/j2se/…
Jay Taylor

2
Saya menggunakan metode 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.
Danny Lo

129

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)


@Fredrik Apa yang terjadi pada konteks Thread ketika interrupt()metode dipanggil? Pertanyaan utama terkait dengan pembuatan log untuk setiap utas baru.
ABcDexter

3
@ ABcDexter Intinya adalah bahwa interupsi tidak mengganggu apa pun, itu hanya sinyal ke kode di utas (atau kode yang dipanggil oleh utas) bahwa seseorang telah memintanya untuk mengganggu apa pun yang dilakukannya. Thread kemudian diharapkan untuk menghentikan pemrosesan dan kembali, seperti jika itu dilakukan dengan melakukan apa yang seharusnya (dan pada saat itu, konteks thread mungkin juga dibuang). OTOH, seandainya Anda benar-benar memaksa menghentikan utasnya, pertanyaan Anda akan sangat bagus dan jawabannya tidak terdefinisi.
Fredrik

64

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 booleanbidang digunakan dimana utas secara berkala memeriksa dan berakhir ketika disetel ke nilai yang sesuai.

Saya tidak akan menggunakan a booleanuntuk memeriksa apakah utasnya harus berakhir . Jika Anda menggunakan volatilesebagai pengubah bidang, ini akan berfungsi andal, tetapi jika kode Anda menjadi lebih kompleks, karena alih-alih menggunakan metode pemblokiran lain di dalam whileloop, 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.


Dan apa yang harus dilakukan jika Anda menjalankan kode yang tidak dipercaya sebagai plugin atau skrip? Java telah menyematkan kotak pasir untuk kode yang tidak dipercaya. Dan kotak pasir itu tidak berguna, itu memungkinkan untuk bekerja tanpa berhenti dengan paksa. Bayangkan Anda sedang menulis browser di java. Kemampuan untuk membunuh skrip halaman sewenang-wenang sangat berharga.
ayvango

@ayvango Maka Anda harus menjalankan skrip itu di kotak pasir Anda sendiri. Kotak pasir Java melindungi mesin dari aplikasi, bukan bagian dari aplikasi satu sama lain.
David Schwartz

@ Davidvidchwartz maksudmu, bahwa aku hanya harus menggunakan platform lain kemudian java?
ayvango

@ayvango Anda masih dapat menggunakan kotak pasir Java untuk melindungi mesin dari aplikasi Anda. Tetapi jika Anda ingin melindungi bagian dari aplikasi Anda dari bagian lain dari aplikasi Anda, Anda harus memilih beberapa alat yang dapat melakukannya.
David Schwartz

@DavidSchwartz ASFAIK alat seperti itu tidak dapat ada jika tidak didukung pada level platform. Tapi tentu saja tugas itu bisa diselesaikan dengan mesin skrip yang sepenuhnya ditafsirkan. Bisa menghitung pengurangan seperti erlang lakukan dan melakukan hal-hal lain.
ayvango

20

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.


2
Sama seperti petunjuk samping: Sebuah variabel sebagai flag hanya berfungsi, ketika utas berjalan dan tidak macet. Thread.interrupt () harus membebaskan utas dari sebagian besar kondisi menunggu (tunggu, tidur, membaca jaringan, dan sebagainya). Oleh karena itu Anda tidak boleh pernah menangkap InterruptedException untuk melakukan ini.
ReneS

12
Ini tidak dapat diandalkan; buat "flag" volatileuntuk 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.
erickson

2
Saya tidak mendapatkan "sementara" dalam menjalankan metode. Bukankah ini berarti bahwa apa pun yang ditulis dalam metode run akan diulang? ini bukan sesuatu yang kami ingin utas dilakukan di tempat pertama :(

2
+1 melakukan while (! Thread.currentThread (). IsInteruppted ()) lebih disukai
Toby

2
Kedua kasus gagal, ketika misalnya Anda membuka proses eksternal di dalam while {// open ext process} dan proses itu digantung, sekarang tidak ada utas yang akan terputus atau akan mencapai akhir untuk memeriksa kondisi Boolean Anda, dan Anda menggantung kiri ... coba dengan misalnya meluncurkan konsol python menggunakan java.exec dan mencoba mendapatkan kontrol kembali tanpa menulis keluar, dan lihat apakah ada cara untuk membunuh proses itu dan keluar .... tidak ada cara untuk keluar dari situasi seperti itu ...
Space Rocker

11

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() );

2
Tidak ada alasan sama sekali untuk melakukan ini, karena masih mungkin untuk memanggil publik Thread.stopbahkan jika sudah usang.
Lii

1
@ Lii Thread.stopmelakukan hal yang sama tetapi juga memeriksa akses dan izin. Penggunaannya Thread.stopagak jelas, dan saya tidak ingat alasan mengapa saya menggunakan Thread.stop0itu. Mungkin Thread.stoptidak berfungsi untuk kasus khusus saya (Weblogic on Java 6). Atau mungkin karena Thread.stopsudah usang dan menyebabkan peringatan.
VadimPlatonov

1
Dalam skenario saya ini adalah satu-satunya cara untuk menghentikan utas berjalan tanpa akhir. Untuk beberapa alasan .stop () tidak menghentikan utas, tetapi stop0 () tidak
fiffy

10

Saya ingin menambahkan beberapa pengamatan, berdasarkan komentar yang telah terkumpul.

  1. Thread.stop() akan menghentikan utas jika manajer keamanan mengizinkannya.
  2. 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?
  3. Anda tidak boleh berhenti menghentikan utas pekerja kontainer. Jika Anda ingin menjalankan kode yang cenderung hang, (hati-hati) mulai thread daemon baru dan awasi, matikan jika perlu.
  4. stop()membuat ThreadDeathErrorkesalahan baru pada utas panggilan dan kemudian melemparkan kesalahan itu pada utas target . Oleh karena itu, jejak tumpukan umumnya tidak berharga.
  5. Di JRE 6, stop()periksa dengan manajer keamanan dan kemudian panggil panggilan stop1()itu stop0(). stop0()adalah kode asli
  6. Sampai dengan Java 13 Thread.stop()belum dihapus (belum), tetapi Thread.stop(Throwable)sudah dihapus di Java 11. ( milis , JDK-8204243 )

8

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.


Jika operasi jaringan sudah dibatalkan dengan aman, cukup sela utas. Jika operasi jaringan tidak dapat dibatalkan dengan aman, Anda tidak dapat menelepon 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 interruptuntuk itu.
David Schwartz

"Jadi ketidakmampuan untuk dengan paksa menghentikan utas itu aneh." - ... sampai Anda melihat secara mendalam (seperti yang telah dilakukan oleh perancang Java) dan menyimpulkan bahwa tidak ada solusi yang layak secara teknis yang tidak lebih buruk daripada mencela stop.
Stephen C

5

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.


Terima kasih! Persis apa yang saya cari!
Denis Kokorin

4

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.


AFAIK semakin banyak layanan yang menjadi hibrid dan menggunakan lingkungan terkelola untuk mengeksekusi kode pihak ke-3 (plugin, skrip, dll.) Yang tidak sepenuhnya mereka kontrol atas kode tersebut, tampaknya tidak masuk akal untuk sepenuhnya mengambil utas. karena bagi teknisi servis, keadaan hidup-dan-melayani dapat jauh lebih baik daripada keadaan tidak-dilayani (baik karena menggantung (yang menghilangkan utas), atau sibuk perulangan tak terbatas (yang menghilangkan inti))
Weipeng L

3

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”);

http://anandsekar.github.io/cancel-support-for-threads/


2

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 :).


1

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:

  • Penggunaan bendera volatil yang dibagikan
  • Penggunaan pasangan metode Thread.interrupt () dan Thread.interrupted ().

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:

https://www.securecoding.cert.org/confluence/display/java/THI05-J.+Do+not+use+Thread.stop%28%29+to+terminate+threads


Karena program tidak lagi ditulis oleh pengembang tunggal, membunuh utas sering diperlukan. Karena itu tidak dapat dianggap pemrograman yang buruk. Saya tidak bisa membayangkan Linux tanpa membunuh. Ketidakmampuan untuk membunuh utas adalah cacat Java.
Pavel Niedoba

1
Luar biasa, Tn. Benar ... Bagaimana jika Anda harus memanggil perpustakaan pihak ke-3, yang tidak dapat Anda kendalikan dan yang memiliki batas waktu kereta dan mungkin hang sekali setiap 1000-2000 kali ketika dieksekusi? Praktek pemrograman yang buruk ya? Yah, Anda tidak selalu dapat memiliki akses ke kode yang Anda gunakan. Pokoknya, op sedang bertanya bagaimana cara membunuh utas bukan bagaimana mengendalikan alirannya ketika mendesain kodenya sendiri ...
Arturas M

Pertanyaannya adalah apa yang akan terjadi ketika Anda membunuh utas yang telah dimiliki mutex atau memiliki blok memori yang dialokasikan, atau yang harus menghasilkan beberapa peristiwa atau data yang menunggu utas lainnya? Apa yang akan terjadi dengan sisa logika aplikasi Anda? Anda akan selalu berisiko bahwa masalah kecil dan terbukti akan diubah menjadi masalah kompleks yang akan sulit untuk direproduksi dan diselidiki. Membunuh utas tidak aman karena dapat meninggalkan aplikasi Anda di sejumlah negara tidak konsisten yang berbeda. Lihatlah informasi dari tautan di cert.org.
ZarathustrA

Kami memiliki utas pengendali yang pada kondisi tertentu dapat memutuskan bahwa seluruh perhitungan menjadi sia-sia. Banyak runnables yang berbeda yang melakukan pekerjaan sebenarnya perlu berhamburan dengan beberapa varian isInterrupted () di tempat yang nyaman - betapa mengerikan! Akan jauh lebih baik jika controller menyebabkan ThreadDeath muncul entah dari mana, dengan rapi membuka semua blok yang disinkronkan & akhirnya. Semua orang mengatakan ini sangat rawan kesalahan, tetapi untuk Thread yang tidak berhubungan, saya tidak mengerti mengapa.
Daniel


1

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;
 }

2
kata kunci yang mudah menguap harus ditambahkan ke shouldCheckUpdates, jika kompiler dioptimalkan dengan utas penyimpanan lokal.
Clinux

1

'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");

    }

}

kata kunci yang mudah menguap harus ditambahkan ke shouldStop variabel, dalam hal kompiler mengoptimalkan dengan thread penyimpanan lokal.
Oleksii Kyslytsyn

0

Thread.stop sudah usang jadi bagaimana kita menghentikan utas di java?

Selalu gunakan metode interupsi dan masa depan untuk meminta pembatalan

  1. Ketika tugas merespons sinyal interupsi, misalnya, blokir metode antrian ambil.
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);
}
  1. Ketika tugas tidak menanggapi sinyal interupsi. Misalkan tugas melakukan soket I / O yang tidak menanggapi sinyal interupsi dan dengan demikian menggunakan pendekatan di atas tidak akan membatalkan tugas, masa depan akan habis tetapi pembatalan blok akhirnya tidak akan berpengaruh , utas akan terus mendengarkan soket. Kita dapat menutup soket atau memanggil metode tutup pada koneksi jika diterapkan oleh kolam.
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);
                }
            }

        };
    }
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.