CodeGym /جاوا بلاگ /Random-SD /جاوا ۾ پريتم حوالا
John Squirrels
سطح
San Francisco

جاوا ۾ پريتم حوالا

گروپ ۾ شايع ٿيل
سلام اڄ جي بحث ۾، اسان جاوا ۾ "پريت حوالن" (PhantomReferences) بابت تفصيل سان ڳالهائينداسين. هي ڪهڙي قسم جا حوالا آهن؟ انهن کي ”پريت حوالو“ ڇو سڏيو وڃي ٿو؟ اهي ڪيئن استعمال ڪيا ويا آهن؟ جيئن توهان کي ياد هوندو، جاوا وٽ 4 قسم جا حوالا آهن:
  1. StrongReference (عام حوالا جيڪي اسان ٺاهيندا آهيون جڏهن هڪ اعتراض ٺاهي رهيا آهيون):

    Cat cat = new Cat()

    هن مثال ۾، ٻلي هڪ مضبوط حوالو آهي.

  2. نرم حوالو (نرم حوالو). اسان کي اهڙن حوالن جو سبق هو.

  3. ڪمزور حوالو (ضعيف حوالو). هتي انهن جي باري ۾ هڪ سبق پڻ هو .

  4. PhantomReference (پريت جو حوالو).

آخري ٽي عام قسم جا آھن قسم جي پيٽرولن سان (مثال طور، SoftReference<Integer> , WeakReference<MyClass> ). SoftReference ، WeakReference ، ۽ PhantomReference ڪلاس ريفرنس ڪلاس مان ورثي ۾ مليا آھن . انهن طبقن سان ڪم ڪرڻ وقت سڀ کان اهم طريقا آهن:
  • get() - حوالو ڏنل اعتراض موٽائي ٿو؛

  • صاف () - اعتراض جي حوالي سان هٽائي ٿو.

توهان انهن طريقن کي ياد ڪندا سبقن مان SoftReference ۽ WeakReference . اهو ياد رکڻ ضروري آهي ته اهي مختلف قسم جي حوالن سان مختلف ڪم ڪن ٿا. اڄ اسان پهرين ٽن قسمن ۾ نه ٿا وڃون. ان جي بدران، اسان پريتم حوالن بابت ڳالهائينداسين. اسان حوالن جي ٻين قسمن تي رابطو ڪنداسين، پر صرف ان حوالي سان ته اهي پريتم حوالن کان ڪيئن مختلف آهن. اچو ته هلون! :) سان شروع ڪرڻ لاء، ڇو اسان کي پريت حوالن جي ضرورت آهي؟ جئين توهان کي خبر آهي، گندگي ڪليڪٽر (gc) غير ضروري جاوا شين جي استعمال ڪيل ياداشت کي جاري ڪري ٿو. ڪليڪٽر هڪ اعتراض کي ٻن "پاس" ۾ حذف ڪري ٿو. پهرين پاس ۾، اهو صرف شيون ڏسي ٿو، ۽، جيڪڏهن ضروري هجي ته، انهن کي "غير ضروري" طور نشان لڳايو (مطلب، "ختم ٿيڻ"). جيڪڏهن finalize()طريقو اعتراض لاء ختم ڪيو ويو آهي، ان کي سڏيو ويندو آهي. يا ٿي سگهي ٿو اهو نه سڏيو ويو آهي - اهو سڀ ان تي منحصر آهي ته ڇا توهان خوش قسمت آهيو. توھان کي شايد ياد ھوندو آھي ته finalize()ٿڪل آھي :) گاربيج ڪليڪٽر جي سيڪنڊ پاس ۾، اعتراض ختم ٿي ويو آھي ۽ ياداشت آزاد ٿي وئي آھي. ڪچرو گڏ ڪندڙ جو غير متوقع رويو اسان لاءِ ڪيترائي مسئلا پيدا ڪري ٿو. اسان کي خبر ناهي ته ڪچرو ڪليڪٽر ڪڏهن هلڻ شروع ڪندو. اسان کي خبر ناهي ته اهو finalize()طريقو سڏيو ويندو. ان سان گڏ، ڪنهن شئي جو هڪ مضبوط حوالو ٺاهي سگهجي ٿو جڏهن ان جي finalize()طريقي تي عمل ڪيو پيو وڃي، انهي صورت ۾ اعتراض کي ختم نه ڪيو ويندو. پروگرامن لاءِ جيڪي دستياب ميموري تي ڳري مطالبا ڪن ٿا، اهو آساني سان ٿي سگھي ٿو OutOfMemoryError. هي سڀ اسان کي پريتم حوالن کي استعمال ڪرڻ لاء زور ڏئي ٿو . حقيقت اها آهي ته هي ردي جي ڪليڪٽر جي رويي کي تبديل ڪري ٿو. جيڪڏهن اعتراض صرف پريتم حوالو آهي، پوء:
  • ان جو حتمي () طريقو سڏيو ويندو آهي (جيڪڏهن اهو ختم ڪيو ويو آهي)

  • جيڪڏهن ڪا به تبديلي نه ايندي آهي هڪ ڀيرو finalize() طريقو ختم ٿي ويندو آهي ۽ اعتراض اڃا به ڊهي سگهجي ٿو، پوءِ اعتراض جو پريتم حوالو هڪ خاص قطار ۾ رکيل آهي: ReferenceQueue .

سمجھڻ لاءِ سڀ کان وڌيڪ اھم شيءِ آھي جڏھن پريت حوالن سان ڪم ڪري رھيو آھي ته اھو اعتراض ميموري مان ختم نه ڪيو ويو آھي جيستائين ان جو پريتم حوالو ھن قطار ۾ نه آھي. اهو ختم ڪيو ويندو صرف صاف () طريقي سان سڏيو ويندو آهي پريتم ريفرنس تي. اچو ته هڪ مثال ڏسو. پهرين، اسان هڪ ٽيسٽ ڪلاس ٺاهينداسين جيڪو ڪنهن قسم جي ڊيٽا کي ذخيرو ڪندو.
public class TestClass {
   private StringBuffer data;
   public TestClass() {
       this.data = new StringBuffer();
       for (long i = 0; i < 50000000; i++) {
           this.data.append('x');
       }
   }
   @Override
   protected void finalize() {
       System.out.println("The finalize method has been called on the TestClass object");
   }
}
جڏهن اسان شيون ٺاهي سگهون ٿا، اسان ارادي طور تي انهن کي هڪ وڏو "لوڊ" ڏينداسين (هر اعتراض ۾ 50 ملين "x" اکرن کي شامل ڪندي) وڌيڪ يادگيري وٺڻ لاء. اضافي طور تي، اسان کي ختم ڪريون ٿا finalize() طريقو اهو ڏسڻ لاءِ ته اهو هليو وڃي ٿو. اڳيون، اسان کي ھڪڙي طبقي جي ضرورت آھي جيڪا ورثي ۾ ملندي PhantomReference . اسان کي اهڙي طبقي جي ضرورت ڇو آهي؟ اهو سڀ ڪجهه سڌو آهي. اهو اسان کي اضافي منطق شامل ڪرڻ جي اجازت ڏيندو clear() طريقي جي تصديق ڪرڻ لاءِ ته پريتم ريفرنس واقعي صاف ٿي چڪو آهي (جنهن جو مطلب آهي اعتراض کي ختم ڪيو ويو آهي).
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

public class MyPhantomReference<TestClass> extends PhantomReference<TestClass> {

   public MyPhantomReference(TestClass obj, ReferenceQueue<TestClass> queue) {

       super(obj, queue);

       Thread thread = new QueueReadingThread<TestClass>(queue);

       thread.start();
   }

   public void cleanup() {
       System.out.println("Cleaning up a phantom reference! Removing an object from memory!");
       clear();
   }
}
اڳيون، اسان کي هڪ الڳ ٿريڊ جي ضرورت آهي جيڪا ڪچري جي ڪليڪٽر جي ڪم ڪرڻ لاءِ انتظار ڪندي، ۽ پريتم لنڪ اسان جي ReferenceQueue ۾ ظاهر ٿيندا . جيئن ئي اهڙو حوالو قطار ۾ ختم ٿئي ٿو، صاف () طريقو ان تي سڏيو ويندو آهي:
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;

public class QueueReadingThread<TestClass> extends Thread {

   private ReferenceQueue<TestClass> referenceQueue;

   public QueueReadingThread(ReferenceQueue<TestClass> referenceQueue) {
       this.referenceQueue = referenceQueue;
   }

   @Override
   public void run() {

       System.out.println("The thread monitoring the queue has started!");
       Reference ref = null;

       // Wait until the references appear in the queue
       while ((ref = referenceQueue.poll()) == null) {

           try {
               Thread.sleep(50);
           }

           catch (InterruptedException e) {
               throw new RuntimeException("Thread " + getName() + " was interrupted!");
           }
       }

       // As soon as a phantom reference appears in the queue, clean it up
       ((MyPhantomReference) ref).cleanup();
   }
}
۽ آخر ۾، اسان کي main() ميٿڊ جي ضرورت آھي، جنھن کي اسين الڳ Main ڪلاس ۾ رکنداسين . انهي طريقي ۾، اسان هڪ TestClass اعتراض ٺاهينداسين ، ان لاء هڪ پريتم حوالو، ۽ پريتم حوالن لاء هڪ قطار. ان کان پوء، اسان گندي ڪليڪٽر کي سڏينداسين ۽ ڏسو ته ڇا ٿئي :)
import java.lang.ref.*;

public class Main {

   public static void main(String[] args) throws InterruptedException {
       Thread.sleep(10000);

       ReferenceQueue<TestClass> queue = new ReferenceQueue<>();
       Reference ref = new MyPhantomReference<>(new TestClass(), queue);

       System.out.println("ref = " + ref);

       Thread.sleep(5000);

       System.out.println("Collecting garbage!");

       System.gc();
       Thread.sleep(300);

       System.out.println("ref = " + ref);

       Thread.sleep(5000);

       System.out.println("Collecting garbage!");

       System.gc();
   }
}
ڪنسول آئوٽ:

ref = MyPhantomReference@4554617c 
The thread monitoring the queue has started! 
Collecting garbage! 
The finalize method has been called on the TestClass object 
ref = MyPhantomReference@4554617c 
Collecting garbage! 
Cleaning up a phantom reference! 
Removing an object from memory! 
اسان هتي ڇا ٿا ڏسو؟ سڀ ڪجهه ٿيو جيئن اسان رٿابندي ڪئي! اسان جي اعتراض جو حتمي () طريقو ختم ڪيو ويو آهي ۽ ان کي سڏيو ويو جڏهن ڪچرو ڪليڪٽر هلائي رهيو هو. اڳيون، پريتم جو حوالو ReferenceQueue ۾ رکيو ويو . جڏهن ته اتي، ان جو صاف () طريقو سڏيو ويندو هو (جنهن جي اندر اسان سڏيو ويندو آهي cleanup() ڪنسول ڏانهن ٻاھر ڪڍڻ لاء). آخرڪار، اعتراض کي ميموري مان ختم ڪيو ويو. هاڻي توهان ڏسندا ته اهو ڪيئن ڪم ڪري ٿو :) يقينا، توهان کي پريتم حوالن جي باري ۾ سڀني نظريي کي ياد ڪرڻ جي ضرورت ناهي. پر اهو سٺو ٿيندو جيڪڏهن توهان گهٽ ۾ گهٽ مکيه نقطا ياد رکو. پهريون، اهي سڀ کان ڪمزور حوالا آهن. اهي راند ۾ تڏهن اچن ٿا جڏهن اعتراض جا ٻيا حوالا باقي نه بچيا آهن. حوالن جي لسٽ جيڪا اسان مٿي ڏني آهي ان کي مضبوط کان ڪمزور ۾ هيٺئين ترتيب سان ترتيب ڏنو ويو آهي: مضبوط حوالو -> نرم حوالو -> ڪمزور حوالو -> پريتم حوالو هڪ پريتم حوالو جنگ ۾ صرف ان وقت داخل ٿئي ٿو جڏهن اسان جي اعتراض لاءِ ڪو مضبوط، نرم يا ڪمزور حوالو نه هجي: ) ٻيو، get() طريقو هميشه هڪ پريتم حوالي لاءِ null موٽائي ٿو . ھتي ھڪڙو سادو مثال آھي جتي اسان ٺاھيون ٿا ٽن مختلف قسمن جا حوالا ٽن مختلف قسمن جي ڪارن لاءِ:
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;

public class Main {

   public static void main(String[] args) {

       Sedan sedan = new Sedan();
       HybridAuto hybrid = new HybridAuto();
       F1Car f1car = new F1Car();

       SoftReference<Sedan> softReference = new SoftReference<>(sedan);
       System.out.println(softReference.get());

       WeakReference<HybridAuto> weakReference = new WeakReference<>(hybrid);
       System.out.println(weakReference.get());

       ReferenceQueue<F1Car> referenceQueue = new ReferenceQueue<>();

       PhantomReference<F1Car> phantomReference = new PhantomReference<>(f1car, referenceQueue);
       System.out.println(phantomReference.get());

   }
}
ڪنسول آئوٽ:

Sedan@4554617c
HybridAuto@74a14482 
null
get () طريقو نرم ۽ ضعيف حوالن لاءِ مڪمل طور تي عام شيون واپس آيو، پر اهو پريتم حوالي لاءِ null موٽي آيو. ٽيون، پريتم حوالا خاص طور تي ياداشت مان شيون حذف ڪرڻ جي پيچيده طريقيڪار ۾ استعمال ٿيندا آهن. بس اهو آهي! :) جيڪو اڄ اسان جو سبق ختم ڪري ٿو. پر توهان اڪيلو نظريي تي پري نه ٿا سگهو، تنهنڪري اهو وقت آهي ڪمن کي حل ڪرڻ ڏانهن موٽڻ! :)
تبصرا
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION