Objek Pengumpul Sampah yang melacak kejadiannya sendiri di Peta internal

Di konstruktor kelas saya, saya memetakan objek saat ini (ini), bersama dengan kuncinya (string yang dimasukkan sebagai parameter dalam konstruktor) ke dalam LinkedHashMap statis sehingga saya dapat mereferensikan objek tersebut dengan string di mana pun saya mungkin membutuhkannya nanti.

Berikut kodenya (jika membantu):

public class DataEntry {
    /** Internal global list of DataEntry objects. */
    private static LinkedHashMap _INTERNAL_LIST;

    /** The data entry's name. */
    private String NAME;

    /** The value this data entry represents. */
    private Object VALUE;


    /** Defines a DataEntry object with a name and a value. */
    public DataEntry( String name, Object value )
    {
        if( _INTERNAL_LIST == null )
        {
            _INTERNAL_LIST = new LinkedHashMap();
        }

        _INTERNAL_LIST.put( name, this );

        NAME = name;
        VALUE = value;
    }
}

Masalah? Contoh kelas ini tidak akan mengumpulkan sampah setelah saya selesai menggunakannya.

Saya hanya ingin tahu apakah ada cara agar instance kelas ini membersihkan dirinya sendiri ketika saya selesai menggunakannya tanpa harus memanggil metode Hapus() secara manual atau sesuatu setiap kali (untuk menghapus referensinya di LinkedHashMap internal ketika saya saya tidak lagi menggunakannya, maksud saya).


person Daddy Warbox    schedule 06.12.2008    source sumber
comment
Haruskah kelas bekerja di lingkungan yang menggunakan thread? Itu tidak akan terjadi saat ini.   -  person McDowell    schedule 07.12.2008
comment
Apa yang secara spesifik menghentikannya?   -  person Daddy Warbox    schedule 07.12.2008
comment
Variabel statis _INTERNAL_LIST tidak disinkronkan. Ada kemungkinan beberapa thread akan menyebabkan banyak peta diinisialisasi. Selain itu, LinkedHashMap tidak disinkronkan, jadi panggilan sinkron ke put dapat membuat peta dalam keadaan tidak stabil.   -  person McDowell    schedule 07.12.2008
comment
Sebenarnya, saya tidak bisa membayangkan situasi apa pun di mana caching melalui konstruktor adalah ide yang bagus.   -  person McDowell    schedule 07.12.2008
comment
Statika itu buruk. Mengekspos ini di konstruktor itu buruk. Tidak menggunakan final pada bidang ini adalah hal yang buruk. Menggunakan konvensi penamaan yang aneh itu buruk. Melakukan semua hal di atas sangatlah buruk.   -  person Tom Hawtin - tackline    schedule 07.12.2008
comment
Latihan yang baik tidak berarti jongkok bagi saya jika tidak melakukan apa yang saya perlukan. Saya pada akhirnya akan mencoba meningkatkan ke solusi tingkat tinggi yang lebih baik untuk semua ini ketika saya dapat menyelesaikan masalah utama saya.   -  person Daddy Warbox    schedule 07.12.2008


Jawaban (3)


Membuat objek terlihat oleh orang lain sebelum konstruktornya selesai tidak aman untuk thread.

Tidak jelas bagaimana peta digunakan dalam kasus ini, tapi misalkan ada metode statis seperti ini di kelas:

public static DataEntry getEntry(String name) {
  return _INTERNAL_LIST.get(name);
}

Thread lain, yang berjalan secara bersamaan, dapat mengakses DataEntry saat sedang dibuat, dan mulai menggunakan entri dengan VALUE yang belum diinisialisasi. Meskipun Anda menyusun ulang kode dalam konstruktor sehingga menambahkan instance baru ke peta adalah hal terakhir yang Anda lakukan, JVM diperbolehkan untuk menyusun ulang instruksi sehingga objek ditambahkan ke daftar terlebih dahulu. Atau, jika kelas diperluas, inisialisasi subkelas dapat dilakukan setelah objek dipublikasikan.

Jika lebih dari satu thread mengakses interaksi dengan kelas DataEntry, Anda mungkin memiliki bug konkurensi yang bergantung pada platform, terputus-putus, dan sangat sulit didiagnosis.

Artikel, "Konstruksi Aman," oleh Brian Goetz memiliki informasi lebih lanjut tentang topik ini.

Kembali ke pertanyaan awal: menggunakan WeakReference, seperti yang disebutkan oleh orang lain, adalah pendekatan yang baik, tetapi daripada mengulangi setiap entri di peta, saya sarankan membuat pembungkus untuk nilai Anda yang memperluas WeakReference (bisa jadi DataEntry Anda sendiri , atau pembantu), dan mengantri setiap referensi dalam ReferenceQueue. Dengan begitu, Anda dapat dengan cepat melakukan polling pada antrean untuk setiap entri yang dikumpulkan, dan menghapusnya dari peta. Hal ini dapat dilakukan dengan thread latar belakang (memblokir di remove) dimulai di penginisialisasi kelas, atau entri basi apa pun dapat dibersihkan (oleh polling) setiap kali entri baru ditambahkan.

Jika program Anda multi-utas, Anda harus mengabaikan LinkedHashMap untuk peta dari java.util.concurrent, atau bungkus LinkedHashMap dengan Collections.synchronizedMap().

person erickson    schedule 06.12.2008
comment
Terima kasih atas informasi tambahannya. Multi-threading adalah jembatan yang pada akhirnya mungkin harus saya lewati, tetapi untuk saat ini saya hanya mempelajari dasar-dasarnya. Pokoknya saya akan mempertimbangkan pendekatan alternatif itu. - person Daddy Warbox; 07.12.2008

Jadikan nilai WeakReferences (atau SoftReferences) sebagai gantinya. Dengan begitu nilai-nilai tersebut masih bisa menjadi sampah yang dikumpulkan. Tentu saja Anda masih memiliki entri di peta - tetapi Anda dapat secara berkala menghapus peta dari entri mana pun yang Weak/SoftReference-nya sekarang kosong.

person Jon Skeet    schedule 06.12.2008
comment
Sial, kamu mengalahkanku sampai pada referensi yang lemah :) - person Morten Christiansen; 07.12.2008
comment
Sedang sibuk mengedit - WeakHashMap tidak terlalu cocok karena kuncinya yang menjadi lemah, bukan nilainya. Anda sebenarnya harus menulis sesuatu yang serupa, tetapi mungkin tidak perlu terlalu kuat jika Anda hanya menggunakannya untuk satu situasi tertentu. - person Jon Skeet; 07.12.2008
comment
Ok terima kasih. Ya, aku takut akan hal itu. Saya mungkin akan tetap menggunakan metode Hapus dan melakukannya dengan cara yang malas. :P - person Daddy Warbox; 07.12.2008

Apa yang ingin Anda gunakan sepertinya merupakan referensi yang lemah. Konsepnya adalah bahwa referensi yang lemah tidak cukup kuat untuk memaksa suatu objek tidak di-GC. Saya tidak mempunyai banyak pengalaman dengan mereka tetapi Anda dapat mempelajari lebih lanjut di sini.

person Morten Christiansen    schedule 06.12.2008