Mengapa Anda menerapkan finalisasi ()?

371

Saya telah membaca banyak pertanyaan tentang Java pemula finalize()dan merasa agak membingungkan bahwa tidak ada yang benar-benar menjelaskan bahwa menyelesaikan () adalah cara yang tidak dapat diandalkan untuk membersihkan sumber daya. Saya melihat seseorang berkomentar bahwa mereka menggunakannya untuk membersihkan Connections, yang benar-benar menakutkan karena satu-satunya cara untuk sedekat dengan jaminan bahwa Koneksi ditutup adalah dengan mengimplementasikan try (catch) akhirnya.

Saya tidak bersekolah di CS, tetapi saya telah memprogram di Jawa secara profesional selama hampir satu dekade sekarang dan saya belum pernah melihat ada yang menerapkan finalize()sistem produksi. Ini masih tidak berarti bahwa itu tidak memiliki kegunaannya, atau bahwa orang yang telah bekerja dengan saya telah melakukannya dengan benar.

Jadi pertanyaan saya adalah, kasus penggunaan apa yang ada untuk implementasi finalize()yang tidak dapat ditangani dengan lebih andal melalui proses lain atau sintaksis dalam bahasa?

Harap berikan skenario khusus atau pengalaman Anda, cukup mengulangi buku teks Java, atau menyelesaikan penggunaan yang dimaksudkan tidak cukup, karena bukan maksud pertanyaan ini.

Spencer Kormos
sumber
Metode HI finalize () dijelaskan dengan sangat baik di sini howtodoinjava.com/2012/10/31/…
Sameer Kazi
2
Sebagian besar aplikasi dan kode perpustakaan tidak akan pernah digunakan finalize(). Namun, kode pustaka platform , seperti SocketInputStream, yang mengelola sumber daya asli atas nama penelepon, melakukan hal itu untuk meminimalkan risiko kebocoran sumber daya (atau menggunakan mekanisme setara, seperti PhantomReference, yang ditambahkan kemudian.) Jadi ekosistem membutuhkannya , meskipun 99,9999% pengembang tidak akan pernah menulis satu pun.
Brian Goetz

Jawaban:

230

Anda bisa menggunakannya sebagai backstop untuk objek yang memegang sumber daya eksternal (soket, file, dll). Menerapkan close()metode dan dokumen yang perlu dipanggil.

Terapkan finalize()untuk melakukan close()pemrosesan jika Anda mendeteksinya belum dilakukan. Mungkin dengan sesuatu yang dibuang untuk stderrmenunjukkan bahwa Anda membersihkan setelah penelepon kereta.

Ini memberikan keamanan ekstra dalam situasi yang luar biasa / kereta. Tidak setiap penelepon akan melakukan try {} finally {}hal yang benar setiap saat. Sayangnya, tetapi berlaku di sebagian besar lingkungan.

Saya setuju bahwa ini jarang dibutuhkan. Dan seperti yang ditunjukkan komentator, ia hadir dengan overhead GC. Hanya gunakan jika Anda membutuhkan keamanan "sabuk dan suspender" di aplikasi yang sudah berjalan lama.

Saya melihat bahwa pada Java 9, Object.finalize()sudah usang! Mereka mengarahkan kita ke java.lang.ref.Cleanerdan java.lang.ref.PhantomReferencesebagai alternatif.

John M
sumber
44
Pastikan saja bahwa pengecualian tidak pernah dilemparkan oleh finalize (), atau pengumpul sampah tidak akan melanjutkan pembersihan objek itu, dan Anda akan mendapatkan kebocoran memori.
skaffman
17
Finalisasi tidak dijamin akan dipanggil, jadi jangan mengandalkan itu melepaskan sumber daya.
flicken
19
skaffman - Saya tidak percaya itu (selain dari implementasi JVM kereta). Dari Object.finalize () javadoc: Jika pengecualian tanpa tertangkap dilemparkan dengan metode finalisasi, pengecualian diabaikan dan finalisasi objek itu berakhir.
John M
4
Proposal Anda dapat menyembunyikan bug orang (tidak menelepon dekat) untuk waktu yang lama. Saya tidak akan merekomendasikan untuk melakukannya.
kohlerm
64
Saya sebenarnya telah menggunakan finalisasi untuk alasan yang tepat ini. Saya mewarisi kode dan itu sangat buggy dan memiliki kecenderungan untuk membiarkan koneksi database terbuka. Kami memodifikasi koneksi untuk memuat data tentang kapan dan di mana mereka dibuat dan kemudian diimplementasikan menyelesaikan untuk mencatat informasi ini jika koneksi tidak ditutup dengan benar. Ternyata sangat membantu untuk melacak koneksi yang tidak tertutup.
brainimus
173

finalize()adalah petunjuk bagi JVM bahwa mungkin baik untuk mengeksekusi kode Anda pada waktu yang tidak ditentukan. Ini bagus ketika Anda ingin kode gagal dijalankan secara misterius.

Melakukan sesuatu yang signifikan dalam finalizer (pada dasarnya apa pun kecuali logging) juga baik dalam tiga situasi:

  • Anda ingin bertaruh bahwa objek yang difinalisasi lainnya masih dalam keadaan yang dianggap valid oleh program Anda.
  • Anda ingin menambahkan banyak kode pemeriksaan ke semua metode semua kelas Anda yang memiliki finalizer, untuk memastikan mereka berperilaku dengan benar setelah finalisasi.
  • Anda ingin secara tidak sengaja menghidupkan kembali objek yang sudah jadi, dan menghabiskan banyak waktu untuk mencari tahu mengapa mereka tidak berfungsi, dan / atau mengapa mereka tidak selesai ketika mereka akhirnya dilepaskan.

Jika Anda merasa Anda perlu menyelesaikan (), kadang-kadang yang Anda inginkan adalah referensi hantu (yang dalam contoh yang diberikan dapat menyimpan referensi keras ke koneksi yang digunakan oleh referensi dan, dan menutupnya setelah referensi hantu telah antri). Ini juga memiliki properti yang mungkin tidak pernah dijalankan secara misterius, tetapi setidaknya ia tidak dapat memanggil metode atau menghidupkan kembali objek yang telah diselesaikan. Jadi itu tepat untuk situasi di mana Anda tidak perlu benar-benar menutup koneksi itu dengan bersih, tetapi Anda cukup ingin, dan klien dari kelas Anda tidak dapat atau tidak akan menyebut diri mereka sendiri (yang sebenarnya cukup adil - apa' Apakah gunanya memiliki pengumpul sampah sama sekali jika Anda mendesain antarmuka yang memerlukan tindakan khusus sebelum pengumpulan? Itu hanya menempatkan kita kembali pada zaman malloc / gratis.)

Lain kali Anda membutuhkan sumber daya yang Anda pikir Anda kelola menjadi lebih kuat. Misalnya, mengapa Anda harus menutup koneksi itu? Pada akhirnya harus didasarkan pada beberapa jenis I / O yang disediakan oleh sistem (socket, file, apa pun), jadi mengapa Anda tidak dapat mengandalkan sistem untuk menutupnya untuk Anda ketika sumber daya level terendah diberikan? Jika server di ujung yang lain benar-benar meminta Anda untuk menutup koneksi dengan bersih daripada menjatuhkan soket, lalu apa yang akan terjadi ketika seseorang tersandung kabel listrik dari mesin yang kode Anda jalani, atau jaringan intervening padam?

Penafian: Saya pernah mengerjakan implementasi JVM di masa lalu. Saya benci finalizers.

Steve Jessop
sumber
76
Terpilih untuk keadilan sarkasme yang ekstrem.
Persepsi
32
Ini tidak menjawab pertanyaan; itu hanya mengatakan semua kekurangan finalize()tanpa memberikan alasan seseorang benar-benar ingin menggunakannya.
Mekanik keong
1
@supercat: referensi hantu (dalam hal ini semua referensi) diperkenalkan di Jawa 2
Steve Jessop
1
@supercat: maaf ya, dengan "referensi" yang saya maksud java.lang.ref.Referencedan subkelasnya. Java 1 memang memiliki variabel :-) Dan ya, itu juga finalizer.
Steve Jessop
2
@SteveJessop: Jika konstruktor kelas dasar meminta entitas lain untuk mengubah keadaan mereka atas nama objek yang sedang dibangun (pola yang sangat umum), tetapi inisialisasi bidang kelas turunan melempar pengecualian, objek yang dibangun sebagian harus segera membersihkan setelah itu sendiri (yaitu memberitahukan entitas-entitas luar layanan mereka tidak lagi diperlukan), tetapi baik Java maupun .NET tidak menawarkan pola bersih-bersih yang dapat digunakan. Memang, mereka tampaknya berusaha keras untuk menyulitkan referensi tentang hal yang perlu pembersihan untuk mencapai kode pembersihan.
supercat
57

Aturan sederhana: jangan pernah gunakan finalizer.

Fakta saja bahwa suatu objek memiliki finalizer (terlepas dari kode apa yang dijalankannya) sudah cukup untuk menyebabkan overhead yang cukup besar untuk pengumpulan sampah.

Dari sebuah artikel oleh Brian Goetz:

Objek dengan finalizer (yang memiliki metode finalize () non-trivial) memiliki overhead yang signifikan dibandingkan dengan objek tanpa finalizer, dan harus digunakan dengan hemat. Objek yang dapat diselesaikan adalah lebih lambat untuk dialokasikan dan lebih lambat untuk dikumpulkan. Pada waktu alokasi, JVM harus mendaftarkan objek yang dapat diselesaikan dengan pengumpul sampah, dan (setidaknya dalam implementasi JVM HotSpot) objek yang dapat diselesaikan harus mengikuti jalur alokasi yang lebih lambat daripada kebanyakan objek lainnya. Demikian pula, objek yang dapat diselesaikan lebih lambat untuk dikoleksi juga. Dibutuhkan setidaknya dua siklus pengumpulan sampah (dalam kasus terbaik) sebelum benda yang dapat diselesaikan dapat direklamasi, dan pengumpul sampah harus melakukan pekerjaan ekstra untuk memanggil finalizer. Hasilnya adalah lebih banyak waktu yang dihabiskan untuk mengalokasikan dan mengumpulkan benda-benda dan lebih banyak tekanan pada pengumpul sampah, karena memori yang digunakan oleh benda yang tidak dapat diselesaikan dapat dipertahankan lebih lama. Gabungkan bahwa dengan fakta bahwa finalizer tidak dijamin untuk berjalan dalam jangka waktu yang dapat diprediksi, atau bahkan sama sekali, dan Anda dapat melihat bahwa ada beberapa situasi yang relatif sedikit dimana finalisasi adalah alat yang tepat untuk digunakan.

Tom
sumber
46

Satu-satunya waktu saya menggunakan menyelesaikan dalam kode produksi adalah untuk mengimplementasikan pemeriksaan bahwa sumber daya objek tertentu telah dibersihkan, dan jika tidak, maka log pesan yang sangat vokal. Itu tidak benar-benar mencoba dan melakukannya sendiri, itu hanya berteriak jika tidak dilakukan dengan benar. Ternyata cukup berguna.

skaffman
sumber
34

Saya sudah melakukan Java secara profesional sejak tahun 1998, dan saya tidak pernah menerapkannya finalize(). Tidak sekali.

Paul Tomblin
sumber
Bagaimana cara menghancurkan objek kelas publik? Ini menyebabkan masalah dalam ADF. Pada dasarnya itu seharusnya memuat ulang halaman (mendapatkan data baru dari API), tetapi mengambil objek lama dan menunjukkan hasilnya
InfantPro'Aravind '
2
@ Finalisasi panggilan InfantPro'Aravind tidak menghapus objek. Ini adalah metode yang Anda terapkan bahwa JVM dapat memilih untuk memanggil jika dan ketika sampah mengumpulkan objek Anda.
Paul Tomblin
@ PaulTomblin, ohk terima kasih untuk detailnya. Adakah saran untuk menyegarkan halaman di ADF?
InfantPro'Aravind '
@ InfantPro'Aravind 'Tidak tahu, tidak pernah menggunakan ADF.
Paul Tomblin
28

Jawaban yang diterima baik, saya hanya ingin menambahkan bahwa sekarang ada cara untuk memiliki fungsi menyelesaikan tanpa benar-benar menggunakannya sama sekali.

Lihatlah kelas "Referensi". Referensi lemah, Referensi Phantom & Referensi Lunak.

Anda dapat menggunakannya untuk menyimpan referensi ke semua objek Anda, tetapi referensi ini SAJA tidak akan menghentikan GC. Hal yang rapi tentang ini adalah Anda dapat memanggilnya metode ketika akan dihapus, dan metode ini dapat dijamin untuk dipanggil.

Adapun finalisasi: Saya menggunakan finalisasi sekali untuk memahami objek apa yang dibebaskan. Anda dapat memainkan beberapa game yang apik dengan statika, penghitungan referensi, dan semacamnya - tetapi itu hanya untuk analisis, tetapi perhatikan kode seperti ini (tidak hanya dalam penyelesaian, tetapi di situlah Anda kemungkinan besar akan melihatnya):

public void finalize() {
  ref1 = null;
  ref2 = null;
  othercrap = null;
}

Ini pertanda bahwa seseorang tidak tahu apa yang mereka lakukan. "Membersihkan" seperti ini hampir tidak pernah dibutuhkan. Ketika kelas GC, ini dilakukan secara otomatis.

Jika Anda menemukan kode seperti itu dalam penyelesaian, dijamin orang yang menulisnya bingung.

Jika ada di tempat lain, bisa jadi kode tersebut merupakan tambalan yang valid untuk model yang buruk (kelas tetap ada untuk waktu yang lama dan untuk beberapa alasan hal-hal yang dirujuk harus dibebaskan secara manual sebelum objek GC'd). Pada umumnya itu karena seseorang lupa untuk menghapus pendengar atau sesuatu dan tidak dapat mengetahui mengapa objek mereka tidak menjadi GC sehingga mereka hanya menghapus hal-hal yang dimaksud dan mengangkat bahu mereka dan berjalan pergi.

Seharusnya tidak pernah digunakan untuk membersihkan segalanya "Lebih cepat".

Bill K.
sumber
3
Referensi hantu adalah cara yang lebih baik untuk melacak objek mana yang dibebaskan, saya pikir.
Bill Michell
2
upvoting untuk memberikan penjelasan terbaik tentang "referensi lemah" yang pernah saya dengar.
sscarduzio
Saya minta maaf karena butuh waktu bertahun-tahun untuk membaca ini, tetapi ini benar-benar tambahan yang bagus untuk jawabannya.
Spencer Kormos
27

Saya tidak yakin apa yang bisa Anda lakukan dengan ini, tapi ...

itsadok@laptop ~/jdk1.6.0_02/src/
$ find . -name "*.java" | xargs grep "void finalize()" | wc -l
41

Jadi saya kira Matahari menemukan beberapa kasus di mana (mereka pikir) itu harus digunakan.

itsadok
sumber
12
Saya kira itu juga pertanyaan "Apakah pengembang Sun akan selalu benar"?
CodeReaper
13
Tetapi berapa banyak dari penggunaan itu yang hanya menerapkan atau menguji dukungan finalizedaripada menggunakannya?
Mekanik keong
Saya menggunakan Windows. Bagaimana Anda akan melakukan hal yang sama di Windows?
gparyani
2
@damryfbfnetsi: Coba instal ack ( beyondgrep.com ) melalui chocolatey.org/packages/ack . Atau gunakan fitur Temukan di File sederhana di $FAVORITE_IDE.
Brian Cline
21
class MyObject {
    Test main;

    public MyObject(Test t) {    
        main = t; 
    }

    protected void finalize() {
        main.ref = this; // let instance become reachable again
        System.out.println("This is finalize"); //test finalize run only once
    }
}

class Test {
    MyObject ref;

    public static void main(String[] args) {
        Test test = new Test();
        test.ref = new MyObject(test);
        test.ref = null; //MyObject become unreachable,finalize will be invoked
        System.gc(); 
        if (test.ref != null) System.out.println("MyObject still alive!");  
    }
}

====================================

hasil:

This is finalize

MyObject still alive!

=====================================

Jadi, Anda dapat membuat instance yang tidak terjangkau dapat dicapai dalam metode finalisasi.

Kiki
sumber
21
Untuk beberapa alasan, kode ini membuat saya berpikir tentang film zombie. Kamu
gambarkan objekmu
di atas adalah kode yang baik. Saya bertanya-tanya bagaimana membuat objek dapat dijangkau kembali sekarang.
lwpro2
15
tidak, di atas adalah kode yang buruk. itu adalah contoh mengapa finalisasi itu buruk.
Tony
Ingatlah bahwa meminta System.gc();bukan jaminan bahwa pengumpul sampah akan benar-benar berjalan. Ini adalah kebijakan penuh GC untuk membersihkan tumpukan (mungkin masih ada tumpukan yang cukup bebas di sekitar, mungkin tidak terfragmentasi menjadi banyak, ...). Jadi itu hanya permintaan sederhana dari programmer "tolong, bisakah Anda mendengarkan saya dan lari?" dan bukan perintah "jalankan sekarang seperti yang saya katakan!". Maaf telah menggunakan kata-kata bahasa tetapi kata itu persis bagaimana GC JVM bekerja.
Roland
11

finalize()dapat bermanfaat untuk menangkap kebocoran sumber daya. Jika sumber daya harus ditutup tetapi tidak menulis fakta bahwa itu tidak ditutup ke file log dan tutup. Dengan begitu Anda menghapus kebocoran sumber daya dan memberi diri Anda cara untuk mengetahui bahwa itu telah terjadi sehingga Anda dapat memperbaikinya.

Saya telah pemrograman di Jawa sejak 1.0 alpha 3 (1995) dan saya belum menimpa finalisasi untuk apa pun ...

TofuBeer
sumber
6

Anda tidak harus bergantung pada menyelesaikan () untuk membersihkan sumber daya Anda untuk Anda. menyelesaikan () tidak akan berjalan sampai kelas dikumpulkan sampah, jika demikian. Jauh lebih baik untuk membebaskan sumber daya secara eksplisit ketika Anda selesai menggunakannya.

Bill the Lizard
sumber
5

Untuk menyorot poin dalam jawaban di atas: finalizers akan dieksekusi di thread GC sendirian. Saya telah mendengar tentang demo Sun utama di mana pengembang menambahkan sedikit tidur untuk beberapa finalizers dan sengaja membawa demo 3D yang mewah.

Yang terbaik untuk dihindari, dengan kemungkinan pengecualian dari tes-env diagnostik.

Eckel's Thinking in Java memiliki bagian yang bagus tentang ini.

Michael Easter
sumber
4

Hmmm, saya pernah menggunakannya untuk membersihkan benda-benda yang tidak dikembalikan ke kolam yang ada.

Mereka sering dilewati, jadi tidak mungkin untuk mengatakan kapan mereka bisa kembali ke kolam dengan aman. Masalahnya adalah bahwa itu memberikan penalti besar selama pengumpulan sampah yang jauh lebih besar daripada penghematan dari mengumpulkan benda-benda. Itu dalam produksi selama sekitar satu bulan sebelum saya mencabut seluruh kumpulan, membuat semuanya dinamis dan selesai dengan itu.

Dengarkan
sumber
4

Berhati - hatilah dengan apa yang Anda lakukan dalam finalize(). Terutama jika Anda menggunakannya untuk hal-hal seperti menelepon tutup () untuk memastikan sumber daya dibersihkan. Kami mengalami beberapa situasi di mana kami memiliki pustaka JNI yang ditautkan ke kode java yang sedang berjalan, dan dalam keadaan apa pun di mana kami menggunakan finalize () untuk memanggil metode JNI, kami akan mendapatkan korupsi tumpukan java yang sangat buruk. Korupsi tidak disebabkan oleh kode JNI yang mendasarinya sendiri, semua jejak memori baik-baik saja di perpustakaan asli. Itu hanya fakta bahwa kami memanggil metode JNI dari finalize () sama sekali.

Ini dengan JDK 1.5 yang masih digunakan secara luas.

Kami tidak akan menemukan bahwa ada yang tidak beres sampai beberapa waktu kemudian, tetapi pada akhirnya pelakunya selalu merupakan metode finalisasi () yang memanfaatkan panggilan JNI.

Steven M. Cherry
sumber
3

Saat menulis kode yang akan digunakan oleh pengembang lain yang membutuhkan semacam metode "pembersihan" dipanggil untuk membebaskan sumber daya. Terkadang pengembang lain lupa memanggil metode pembersihan (atau tutup, atau hancurkan, atau apa pun) Anda. Untuk menghindari kemungkinan kebocoran sumber daya, Anda dapat memeriksa dalam metode finalisasi untuk memastikan bahwa metode itu dipanggil dan jika tidak, Anda dapat menyebutnya sendiri.

Banyak pengandar basis data melakukan ini dalam implementasi Pernyataan dan Koneksi mereka untuk memberikan sedikit keamanan terhadap pengembang yang lupa memanggil mereka.

John Meagher
sumber
2

Sunting: Oke, itu benar-benar tidak berhasil. Saya menerapkannya dan berpikir jika gagal kadang-kadang itu tidak masalah bagi saya tetapi bahkan tidak memanggil metode finalisasi sekali saja.

Saya bukan seorang programmer profesional tetapi dalam program saya, saya memiliki case yang saya pikir menjadi contoh dari kasus yang baik menggunakan finalize (), yaitu cache yang menulis kontennya ke disk sebelum dihancurkan. Karena tidak perlu dijalankan setiap kali pada kehancuran, itu hanya mempercepat program saya, saya harap itu tidak salah.

@Override
public void finalize()
{
    try {saveCache();} catch (Exception e)  {e.printStackTrace();}
}

public void saveCache() throws FileNotFoundException, IOException
{
    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("temp/cache.tmp"));
    out.writeObject(cache);
}
pengguna265243
sumber
Saya pikir cache (dari jenis yang Anda akan flush ke disk) adalah contoh yang baik. Dan bahkan jika finalisasi tidak disebut, jangan berkeringat.
foo
2

Mungkin berguna untuk menghapus hal-hal yang telah ditambahkan ke tempat global / statis (tidak perlu), dan perlu dihapus ketika objek dihapus. Contohnya:

    private void addGlobalClickListener () {
        lemahAwtEventListener = WeakAWTEventListener baru (ini);

        Toolkit.getDefaultToolkit (). AddAWTEventListener (lemahAwtEventListener, AWTEvent.MOUSE_EVENT_MASK);
    }

    @Mengesampingkan
    batal dilindungi finalisasi () melempar Throwable {
        super.finalize ();

        if (lemahAwtEventListener! = null) {
            Toolkit.getDefaultToolkit (). RemoveAWTEventListener (lemahAwtEventListener);
        }
    }
Alexander Malfait
sumber
Ini membutuhkan upaya tambahan, karena ketika pendengar memiliki referensi kuat ke thisinstance yang diteruskan ke konstruktor, instance itu tidak akan pernah menjadi tidak terjangkau, oleh karena itu bagaimanapun finalize()juga tidak akan pernah bersih. Jika, di sisi lain, pendengar memegang referensi lemah ke objek itu, seperti namanya, konstruksi ini beresiko dibersihkan pada saat-saat yang seharusnya tidak. Siklus hidup objek bukan alat yang tepat untuk menerapkan semantik aplikasi.
Holger
0

iirc - Anda dapat menggunakan metode finalisasi sebagai cara menerapkan mekanisme penyatuan untuk sumber daya yang mahal - sehingga mereka tidak mendapatkan GC juga.

JGFMK
sumber
0

Sebagai catatan:

Objek yang menimpa menyelesaikan () diperlakukan secara khusus oleh pengumpul sampah. Biasanya, suatu objek segera dihancurkan selama siklus pengumpulan setelah objek tidak lagi dalam ruang lingkup. Namun, objek yang diselesaikan dapat dipindahkan ke antrian, tempat utas finalisasi yang terpisah akan menguras antrian dan menjalankan metode finalize () pada setiap objek. Setelah metode finalisasi () berakhir, objek pada akhirnya akan siap untuk pengumpulan sampah di siklus berikutnya.

Sumber: finalize () usang di java-9

Sudip Bhandari
sumber
0

Sumber daya (File, Socket, Stream dll.) Perlu ditutup setelah kita selesai dengan mereka. Mereka umumnya memiliki close()metode yang biasanya kita sebut dalam finallybagian try-catchpernyataan. Kadang finalize()- kadang juga dapat digunakan oleh beberapa pengembang tetapi IMO yang bukan cara yang cocok karena tidak ada jaminan bahwa penyelesaian akan dipanggil selalu.

Di Java 7 kami telah mendapatkan pernyataan coba-dengan-sumber daya yang dapat digunakan seperti:

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
  // Processing and other logic here.
} catch (Exception e) {
  // log exception
} finally {
  // Just in case we need to do some stuff here.
}

Dalam contoh di atas coba-dengan-sumber daya akan secara otomatis menutup sumber daya BufferedReaderdengan menggunakan close()metode. Jika kita mau, kita juga bisa mengimplementasikan Closeable di kelas kita sendiri dan menggunakannya dengan cara yang sama. IMO sepertinya lebih rapi dan mudah dipahami.

akhil_mittal
sumber
0

Secara pribadi, saya hampir tidak pernah menggunakan finalize()kecuali dalam satu keadaan langka: Saya membuat koleksi tipe generik khusus, dan saya menulis finalize()metode kustom yang melakukan hal berikut:

public void finalize() throws Throwable {
    super.finalize();
    if (destructiveFinalize) {
        T item;
        for (int i = 0, l = length(); i < l; i++) {
            item = get(i);
            if (item == null) {
                continue;
            }
            if (item instanceof Window) {
                ((Window) get(i)).dispose();
            }
            if (item instanceof CompleteObject) {
                ((CompleteObject) get(i)).finalize();
            }
            set(i, null);
        }
    }
}

( CompleteObjectAdalah sebuah antarmuka saya membuat yang memungkinkan Anda menentukan bahwa Anda telah menerapkan jarang-dilaksanakan Objectmetode seperti #finalize(), #hashCode(), dan #clone())

Jadi, menggunakan #setDestructivelyFinalizes(boolean)metode saudari , program menggunakan koleksi saya dapat (membantu) menjamin bahwa menghancurkan referensi ke koleksi ini juga menghancurkan referensi ke isinya dan membuang semua jendela yang mungkin membuat JVM tetap hidup tanpa disengaja. Saya dianggap juga menghentikan semua utas, tetapi itu membuka kaleng cacing yang sama sekali baru.

Supuhstar
sumber
4
Memanggil finalize()pada Anda CompleteObjectcontoh seperti yang Anda lakukan dalam kode di atas menyiratkan bahwa itu mungkin akan dipanggil dua kali, sebagai JVM masih mungkin memanggil finalize()sekali benda-benda ini benar-benar menjadi tidak terjangkau, yang, karena logika finalisasi, mungkin sebelum itu finalize()metode koleksi khusus Anda dipanggil atau bahkan secara bersamaan pada saat yang sama. Karena saya tidak melihat langkah-langkah untuk memastikan keamanan benang dalam metode Anda, Anda tampaknya tidak mengetahui hal ini ...
Holger
0

Jawaban yang diterima mencantumkan bahwa penutupan sumber daya selama penyelesaian dapat dilakukan.

Namun jawaban ini menunjukkan bahwa setidaknya di java8 dengan kompiler JIT, Anda mengalami masalah yang tidak terduga di mana kadang-kadang finalizer dipanggil bahkan sebelum Anda selesai membaca dari aliran yang dikelola oleh objek Anda.

Jadi, bahkan dalam situasi itu penyelesaian panggilan tidak akan direkomendasikan.

Joeblade
sumber
Ini akan berhasil, jika operasi ini membuat thread aman, yang merupakan keharusan, karena finalizers dapat dipanggil oleh utas sewenang-wenang. Karena keselamatan ulir yang diimplementasikan dengan benar menyiratkan bahwa tidak hanya operasi tutup, tetapi juga operasi yang menggunakan sumber daya harus disinkronkan pada objek atau kunci yang sama, akan ada hubungan sebelum-terjadi antara penggunaan dan operasi tutup, yang juga mencegah terlalu dini finalisasi. Tapi, tentu saja, dengan harga tinggi untuk seluruh penggunaan ...
Holger