CodeGym /جاوا بلاگ /Random-UR /جاوا میں فینٹم حوالہ جات
John Squirrels
سطح
San Francisco

جاوا میں فینٹم حوالہ جات

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

    Cat cat = new Cat()

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

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

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

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

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

  • clear() — آبجیکٹ کا حوالہ ہٹاتا ہے۔

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

  • اگر فائنلائز() طریقہ ختم ہونے کے بعد کچھ بھی تبدیل نہیں ہوتا ہے اور آبجیکٹ کو اب بھی حذف کیا جا سکتا ہے، تو آبجیکٹ کا فینٹم حوالہ ایک خاص قطار میں رکھا جاتا ہے: 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" حروف شامل کر کے) تاکہ زیادہ میموری حاصل ہو سکے۔ اس کے علاوہ، ہم فائنلائز() طریقہ کو اوور رائیڈ کرتے ہیں تاکہ یہ دیکھا جا سکے کہ یہ چل رہا ہے۔ اگلا، ہمیں ایک کلاس کی ضرورت ہے جو PhantomReference سے وراثت میں آئے ۔ ہمیں ایسی کلاس کی ضرورت کیوں ہے؟ یہ سب سیدھا ہے۔ یہ ہمیں واضح () طریقہ کار میں اضافی منطق شامل کرنے کی اجازت دے گا تاکہ اس بات کی تصدیق کی جا سکے کہ فینٹم حوالہ واقعی صاف ہو گیا ہے (جس کا مطلب ہے کہ اعتراض کو حذف کر دیا گیا ہے)۔
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 میں ڈال دیا گیا ۔ وہاں رہتے ہوئے، اس کا واضح () طریقہ کہا گیا تھا (جس کے اندر ہم نے کلین اپ () کو کنسول میں آؤٹ پٹ کرنے کے لیے کہا تھا)۔ آخر کار، آبجیکٹ کو میموری سے ڈیلیٹ کر دیا گیا۔ اب آپ دیکھتے ہیں کہ یہ کیسے کام کرتا ہے :) یقیناً، آپ کو فینٹم حوالوں سے متعلق تمام تھیوری کو یاد کرنے کی ضرورت نہیں ہے۔ لیکن یہ اچھا ہو گا اگر آپ کم از کم اہم نکات کو یاد رکھیں۔ سب سے پہلے، یہ سب سے کمزور ترین حوالہ جات ہیں۔ وہ تبھی عمل میں آتے ہیں جب اعتراض کا کوئی دوسرا حوالہ باقی نہ رہے۔ حوالہ جات کی جو فہرست ہم نے اوپر دی ہے اسے مضبوط سے کمزور تک نزولی ترتیب میں ترتیب دیا گیا ہے: 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 () طریقہ نرم اور کمزور حوالوں کے لیے مکمل طور پر عام اشیاء کو واپس کر دیتا ہے، لیکن یہ فینٹم ریفرنس کے لیے کالعدم ہو گیا۔ تیسرا، فینٹم حوالہ جات بنیادی طور پر میموری سے اشیاء کو حذف کرنے کے پیچیدہ طریقہ کار میں استعمال ہوتے ہیں۔ یہی ہے! :) اس سے ہمارا آج کا سبق ختم ہوتا ہے۔ لیکن آپ اکیلے نظریہ پر زیادہ نہیں جا سکتے، لہذا اب وقت آگیا ہے کہ کاموں کو حل کرنے پر واپس جائیں! :)
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION