วัตถุรวบรวมขยะซึ่งติดตามอินสแตนซ์ของตัวเองในแผนที่ภายใน

ในตัวสร้างของคลาสของฉัน ฉันแมปวัตถุปัจจุบัน (สิ่งนี้) พร้อมกับคีย์ของมัน (สตริงที่ป้อนเป็นพารามิเตอร์ในตัวสร้าง) ลงใน LinkedHashMap แบบคงที่ เพื่อให้ฉันสามารถอ้างอิงวัตถุโดย สตริงทุกที่ที่ฉันอาจต้องการมันในภายหลัง

นี่คือรหัส (ถ้าช่วยได้):

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

ปัญหา? อินสแตนซ์ของคลาสนี้จะไม่ถูกเก็บขยะเมื่อฉันใช้งานเสร็จแล้ว

ฉันแค่อยากรู้ว่ามีวิธีใดที่อินสแตนซ์ของคลาสนี้จะทำความสะอาดตัวเองเมื่อฉันใช้งานเสร็จแล้วโดยไม่ต้องเรียกใช้เมธอด Remove() หรือบางอย่างด้วยตนเองในแต่ละครั้ง (เพื่อลบการอ้างอิงใน LinkedHashMap ภายในเมื่อฉัน ฉันหมายถึงว่าไม่ได้ใช้มันอีกต่อไปแล้ว)


person Daddy Warbox    schedule 06.12.2008    source แหล่งที่มา
comment
ชั้นเรียนควรทำงานในสภาพแวดล้อมที่ใช้เธรดหรือไม่ มันจะไม่อยู่ในปัจจุบัน   -  person McDowell    schedule 07.12.2008
comment
อะไรหยุดมันโดยเฉพาะ?   -  person Daddy Warbox    schedule 07.12.2008
comment
ตัวแปรคงที่ _INTERNAL_LIST ไม่ได้รับการซิงโครไนซ์ มีโอกาสที่หลายเธรดจะทำให้หลายแผนที่เริ่มต้นได้ นอกจากนี้ LinkedHashMap จะไม่ซิงโครไนซ์ ดังนั้นการเรียกซิงโครนัสที่ใส่อาจทำให้แผนที่อยู่ในสถานะไม่เสถียร   -  person McDowell    schedule 07.12.2008
comment
จริงๆ แล้ว ฉันไม่สามารถจินตนาการถึงสถานการณ์ใดๆ ที่การแคชผ่าน Constructor เป็นความคิดที่ดีได้   -  person McDowell    schedule 07.12.2008
comment
สถิตยศาสตร์ไม่ดี การเปิดเผยสิ่งนี้ในตัวสร้างเป็นสิ่งที่ไม่ดี การไม่ใช้ขั้นสุดท้ายในฟิลด์เหล่านี้ถือเป็นเรื่องไม่ดี การใช้แบบแผนการตั้งชื่อแปลก ๆ เป็นสิ่งที่ไม่ดี การทำทุกอย่างข้างต้นนั้นแย่มาก   -  person Tom Hawtin - tackline    schedule 07.12.2008
comment
การฝึกฝนที่ดีไม่ได้หมายถึงการหมอบลงสำหรับฉัน หากไม่ได้ทำในสิ่งที่ฉันต้องการให้ทำ ในที่สุดฉันจะพยายามอัปเกรดเป็นโซลูชันระดับสูงที่สวยงามยิ่งขึ้นสำหรับทั้งหมดนี้เมื่อฉันสามารถแก้ไขปัญหาหลักได้   -  person Daddy Warbox    schedule 07.12.2008


คำตอบ (3)


การทำให้วัตถุมองเห็นได้ก่อนที่ตัวสร้างจะเสร็จสมบูรณ์นั้นไม่ปลอดภัยสำหรับเธรด

ยังไม่ชัดเจนว่าแผนที่ถูกใช้อย่างไรในกรณีนี้ แต่สมมติว่ามีวิธีการคงที่เช่นนี้ในชั้นเรียน:

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

เธรดอื่นที่ทำงานพร้อมกัน สามารถเข้าถึง DataEntry ในขณะที่กำลังสร้าง และเริ่มใช้รายการด้วย VALUE ที่ยังไม่ได้เตรียมใช้งาน แม้ว่าคุณจะเรียงลำดับโค้ดใหม่ใน Constructor เพื่อให้การเพิ่มอินสแตนซ์ใหม่ลงในแผนที่เป็นสิ่งสุดท้ายที่คุณทำ JVM ก็ได้รับอนุญาตให้เรียงลำดับคำสั่งใหม่เพื่อให้วัตถุถูกเพิ่มลงในรายการก่อน หรือถ้าคลาสถูกขยาย การเริ่มต้นคลาสย่อยอาจเกิดขึ้นหลังจากที่อ็อบเจ็กต์ได้รับการเผยแพร่แล้ว

หากมีเธรดมากกว่าหนึ่งเธรดเข้าถึงการโต้ตอบกับคลาส DataEntry คุณอาจมีข้อบกพร่องที่เกิดขึ้นพร้อมกันซึ่งขึ้นอยู่กับแพลตฟอร์ม ไม่ต่อเนื่อง และวินิจฉัยได้ยากมาก

บทความ "Safe Construction" โดย Brian Goetz มีข้อมูลเพิ่มเติมเกี่ยวกับหัวข้อนี้

กลับมาที่คำถามเดิม: การใช้ WeakReference ตามที่ผู้อื่นกล่าวถึงเป็นแนวทางที่ดี แต่แทนที่จะวนซ้ำทุกรายการในแผนที่ ฉันขอแนะนำให้สร้าง wrapper สำหรับค่าของคุณที่ขยาย WeakReference (อาจเป็น DataEntry ของคุณเอง หรือตัวช่วย) และเข้าคิวการอ้างอิงแต่ละรายการใน ReferenceQueue. ด้วยวิธีนี้ คุณสามารถสำรวจคิวสำหรับรายการที่รวบรวมได้อย่างรวดเร็ว และลบออกจากแผนที่ ซึ่งสามารถทำได้โดยเธรดพื้นหลัง (การบล็อกบน remove) เริ่มต้นในเครื่องมือเริ่มต้นคลาส หรือรายการเก่าๆ อาจถูกล้าง (โดย การสำรวจความคิดเห็น) ทุกครั้งที่มีการเพิ่มรายการใหม่

หากโปรแกรมของคุณเป็นแบบมัลติเธรด คุณควรละทิ้ง LinkedHashMap สำหรับแผนที่จาก java.util.concurrent หรือล้อม LinkedHashMap ด้วย Collections.synchronizedMap().

person erickson    schedule 06.12.2008
comment
ขอบคุณสำหรับข้อมูลเพิ่มเติม มัลติเธรดเป็นสะพานที่ฉันอาจต้องข้ามไปในที่สุด แต่ตอนนี้ฉันแค่กำลังสับสนกับพื้นฐาน อย่างไรก็ตามฉันจะพิจารณาแนวทางอื่นนั้น - person Daddy Warbox; 07.12.2008

สร้างค่า WeakReferences (หรือ SoftReferences) แทน ด้วยวิธีนี้ค่าต่างๆ ยังคงเป็นขยะที่รวบรวมได้ แน่นอนว่าคุณจะยังคงมีรายการอยู่ในแผนที่ - แต่คุณสามารถล้างแผนที่ของรายการใดๆ ที่ Weak/SoftReference ว่างเปล่าได้เป็นระยะๆ

person Jon Skeet    schedule 06.12.2008
comment
ให้ตายเถอะ คุณเอาชนะฉันด้วยการอ้างอิงที่อ่อนแอ :) - person Morten Christiansen; 07.12.2008
comment
กำลังยุ่งอยู่กับการแก้ไข - WeakHashMap ไม่เหมาะจริงๆ เนื่องจากเป็นคีย์ที่สุดท้ายแล้วอ่อนแอ ไม่ใช่ค่า คุณจะต้องเขียนบางอย่างที่คล้ายกัน แต่อาจจะไม่จำเป็นที่จะต้องทรงพลังขนาดนั้นหากคุณใช้ในสถานการณ์ใดสถานการณ์หนึ่งเท่านั้น - person Jon Skeet; 07.12.2008
comment
โอเคขอบคุณ. ใช่แล้ว ฉันกลัวเรื่องนั้น ฉันอาจจะแค่ใช้วิธี Remove แล้วทำแบบขี้เกียจ :ป - person Daddy Warbox; 07.12.2008

สิ่งที่คุณต้องการใช้ดูเหมือนจะเป็นข้อมูลอ้างอิงที่อ่อนแอ แนวคิดก็คือการอ้างอิงที่อ่อนแอนั้นไม่แข็งแกร่งพอที่จะบังคับวัตถุไม่ให้เป็น GC'ed ฉันไม่ค่อยมีประสบการณ์กับพวกเขามากนัก แต่คุณสามารถเรียนรู้เพิ่มเติมได้ ที่นี่.

person Morten Christiansen    schedule 06.12.2008