JavaRush /جاوا بلاگ /Random-UR /جاوا میں فینٹم ریفرنس

جاوا میں فینٹم ریفرنس

گروپ میں شائع ہوا۔
ہیلو! آج کے سبق میں، ہم جاوا میں فینٹم ریفرینسز کے بارے میں تفصیل سے بات کریں گے۔ یہ کس قسم کے لنکس ہیں، انہیں "پریت" ​​کیوں کہا جاتا ہے اور انہیں کیسے استعمال کیا جائے؟ جیسا کہ آپ کو یاد ہے، جاوا میں 4 قسم کے لنکس ہیں:
  1. StrongReference (باقاعدہ حوالہ جات جو ہم کسی چیز کو بناتے وقت بناتے ہیں):

    Cat cat = new Cat()

    اس مثال میں بلی ایک مضبوط حوالہ ہے۔

  2. نرم حوالہ (نرم حوالہ)۔ ان روابط کے بارے میں ہمارا ایک لیکچر تھا۔

  3. کمزور حوالہ (کمزور حوالہ)۔ ان کے بارے میں یہاں ایک لیکچر بھی تھا ۔

  4. PhantomReference (پریتی حوالہ)۔

آخری تین اقسام کے آبجیکٹ ٹائپ کیے گئے ہیں (مثال کے طور پر، SoftReference<Integer> , WeakReference<MyClass> )۔ کلاسز SoftReference، WeakReferenceاور PhantomReferenceکلاس سے وراثت حاصل کریں Reference۔ ان کلاسوں کے ساتھ کام کرتے وقت سب سے اہم طریقے یہ ہیں:
  • get()- اس چیز کو لوٹاتا ہے جس کا یہ لنک حوالہ دیتا ہے۔

  • clear()- کسی شے کا حوالہ حذف کرتا ہے۔

SoftReferenceآپ کو اور کے بارے میں لیکچرز سے یہ طریقے یاد ہیں WeakReference۔ یہ یاد رکھنا ضروری ہے کہ وہ مختلف قسم کے لنکس کے ساتھ مختلف طریقے سے کام کرتے ہیں۔ آج ہم پہلی تین اقسام پر تفصیل سے غور نہیں کریں گے بلکہ پریت کے لنکس کے بارے میں بات کریں گے۔ ہم دوسری قسم کے لنکس کو بھی چھوئیں گے، لیکن صرف اس حصے میں جہاں ہم اس بارے میں بات کریں گے کہ فینٹم لنکس ان سے کیسے مختلف ہیں۔ جاؤ! :) آئیے اس کے ساتھ شروع کریں کہ ہمیں پہلی جگہ پریت کے لنکس کی ضرورت کیوں ہے۔ جیسا کہ آپ جانتے ہیں، کوڑا جمع کرنے والا (کوڑا جمع کرنے والا یا جی سی) غیر ضروری جاوا اشیاء سے میموری کو آزاد کرنے کا ذمہ دار ہے ۔ کلکٹر اعتراض کو دو "پاس" میں ہٹاتا ہے۔ پہلے پاس پر، یہ صرف اشیاء کو دیکھتا ہے، اور، اگر ضروری ہو تو، انہیں "غیر ضروری اور حذف کیے جانے" کے بطور نشان زد کرتا ہے۔ اگر اس شے کا کوئی طریقہ اوور رائڈ ہو گیا ہے finalize()تو اسے کہا جاتا ہے۔ یا اسے نہیں کہا جاتا ہے - آپ کی قسمت پر منحصر ہے۔ آپ کو شاید یاد ہوگا کہ یہ finalize()ایک ہنگامہ خیز چیز ہے :) کلکٹر کے دوسرے پاس میں، اعتراض کو حذف کر دیا جاتا ہے اور میموری کو آزاد کر دیا جاتا ہے. کچرا اٹھانے والے کا یہ غیر متوقع رویہ ہمارے لیے کئی مسائل پیدا کرتا ہے۔ ہم نہیں جانتے کہ کچرا اٹھانے والا کب کام شروع کرے گا۔ ہم نہیں جانتے کہ طریقہ کار کہا جائے گا یا نہیں finalize()۔ اس کے علاوہ، آپریشن کے دوران finalize()آبجیکٹ کا ایک مضبوط لنک بنایا جا سکتا ہے، اور پھر اسے بالکل بھی حذف نہیں کیا جائے گا۔ میموری کے بھوکے نظاموں پر، یہ آسانی سے ہو سکتا ہے OutOfMemoryError۔ یہ سب ہمیں فینٹم لنکس استعمال کرنے کی طرف دھکیلتا ہے ۔ بات یہ ہے کہ اس سے کچرا اٹھانے والے کے رویے میں تبدیلی آتی ہے۔ اگر آبجیکٹ کے صرف فینٹم لنکس باقی ہیں، تو اس میں ہے:
  • طریقہ کہا جاتا ہے finalize()(اگر یہ اوور رائڈ ہو)؛

  • اگر کام کے بعد finalize()کچھ بھی نہیں بدلا ہے اور آبجیکٹ کو اب بھی ڈیلیٹ کیا جا سکتا ہے، تو اس شے کا فینٹم حوالہ ایک خاص قطار میں رکھا جاتا ہے ReferenceQueue۔

فینٹم حوالہ جات کے ساتھ کام کرتے وقت سمجھنے کی سب سے اہم بات یہ ہے کہ کسی چیز کو میموری سے اس وقت تک نہیں ہٹایا جاتا جب تک کہ اس کا فینٹم حوالہ اس قطار میں موجود ہو ۔ فینٹم لنک کے بعد ہی اسے حذف کیا جائے گا clear()۔ آئیے ایک مثال دیکھتے ہیں۔ سب سے پہلے، آئیے ایک ٹیسٹ کلاس بنائیں جو کچھ ڈیٹا اسٹور کرے گی۔
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("У an object TestClass вызван метод finalize!!!");
   }
}
زیادہ میموری لینے کے لیے ہم جان بوجھ کر اشیاء کو ڈیٹا کے ساتھ "لوڈ" کرتے ہیں (ہر آبجیکٹ میں 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("Очистка фантомной ссылки! Удаление an object из памяти!");
       clear();
   }
}
اس کے بعد، ہمیں ایک علیحدہ دھاگے کی ضرورت ہوگی جو کوڑا اٹھانے والے کے اپنے کام کرنے کا انتظار کرے گا، اور ReferenceQueueہماری قطار میں فینٹم لنکس ظاہر ہوں گے۔ جیسے ہی ایسا کوئی لنک قطار میں آجائے گا، اس کا طریقہ کہا جائے گا cleanup():
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("Поток, отслеживающий очередь, стартовал!");
       Reference ref = null;

       //ждем, пока в очереди появятся ссылки
       while ((ref = referenceQueue.poll()) == null) {

           try {
               Thread.sleep(50);
           }

           catch (InterruptedException e) {
               throw new RuntimeException("Поток " + getName() + " был прерван!");
           }
       }

       //How только в очереди появилась фантомная link - очистить ее
       ((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("Вызывается сборка мусора!");

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

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

       Thread.sleep(5000);

       System.out.println("Вызывается сборка мусора!");

       System.gc();
   }
}
کنسول آؤٹ پٹ: ref = MyPhantomReference@4554617c قطار کی نگرانی کرنے والا تھریڈ شروع ہو گیا ہے! کوڑا اٹھانے کو کہتے ہیں! حتمی طریقہ کو TestClass آبجیکٹ پر بلایا گیا ہے!!! ref = MyPhantomReference@4554617c کوڑا اٹھانے کا مطالبہ کیا جا رہا ہے! پریت کے لنک کو صاف کرنا! میموری سے کسی چیز کو ہٹانا! ہم یہاں کیا دیکھتے ہیں؟ جیسا کہ ہم نے منصوبہ بنایا تھا سب کچھ ہوا! ہماری آبجیکٹ کلاس میں ایک طریقہ اوور رائیڈ کیا گیا تھا finalize()اور اسے اس وقت بلایا گیا جب کلکٹر چل رہا تھا۔ اگلا، فینٹم لنک قطار میں کھڑا تھا ReferenceQueue۔ وہاں اس کے پاس ایک طریقہ تھا clear()(جس سے ہم نے cleanup()کنسول میں آؤٹ پٹ شامل کیا)۔ نتیجے کے طور پر، اعتراض کو میموری سے ہٹا دیا گیا تھا. اب آپ دیکھتے ہیں کہ یہ کیسے کام کرتا ہے :) یقیناً، آپ کو فینٹم لنکس سے منسلک تمام تھیوری کو یاد کرنے کی ضرورت نہیں ہے۔ لیکن یہ اچھا ہو گا اگر آپ کم از کم اہم نکات کو یاد رکھیں۔ سب سے پہلے ، یہ سب سے کمزور روابط ہیں۔ وہ تبھی عمل میں آتے ہیں جب اعتراض کا کوئی دوسرا حوالہ نہ ہو۔ لنکس کی جو فہرست ہم نے اوپر دی ہے وہ طاقت کے نزولی ترتیب میں ہے: StrongReference-> SoftReference-> WeakReference-> PhantomReference فینٹم لنک اسی وقت جنگ میں داخل ہوگا جب ہمارے اعتراض پر کوئی مضبوط، نرم یا کمزور لنکس نہ ہوں :) دوسرا طریقہ 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