CodeGym/Java Blog/Random/Mga Phantom na Sanggunian sa Java
John Squirrels
Antas
San Francisco

Mga Phantom na Sanggunian sa Java

Nai-publish sa grupo
Hi! Sa talakayan ngayon, tatalakayin natin nang detalyado ang tungkol sa "mga phantom reference" (PhantomReference) sa Java. Anong uri ng mga sanggunian ang mga ito? Bakit sila tinawag na "phantom references"? Paano ginagamit ang mga ito? Kung maaalala mo, ang Java ay may 4 na uri ng mga sanggunian:
  1. StrongReference (ordinaryong mga sanggunian na ginagawa namin kapag lumilikha ng isang bagay):

    Cat cat = new Cat()

    Sa halimbawang ito, ang pusa ay isang malakas na sanggunian.

  2. SoftReference (malambot na sanggunian). Nagkaroon kami ng aral tungkol sa mga ganitong sanggunian.

  3. WeakReference (mahinang sanggunian). Nagkaroon din ng aral tungkol sa kanila dito .

  4. PhantomReference (phantom reference).

Ang huling tatlo ay mga generic na uri na may mga parameter ng uri (halimbawa, SoftReference<Integer> , WeakReference<MyClass> ). Ang SoftReference , WeakReference , at PhantomReference na mga klase ay minana mula sa Reference class. Ang pinakamahalagang paraan kapag nagtatrabaho sa mga klase na ito ay:
  • get() - ibinabalik ang reference na bagay;

  • clear() - inaalis ang reference sa object.

Naaalala mo ang mga pamamaraang ito mula sa mga aralin sa SoftReference at WeakReference . Mahalagang tandaan na ang mga ito ay gumagana nang iba sa iba't ibang uri ng mga sanggunian. Ngayon ay hindi tayo sumisid sa unang tatlong uri. Sa halip, pag-uusapan natin ang tungkol sa phantom reference. Tatalakayin natin ang iba pang mga uri ng mga sanggunian, ngunit may kinalaman lamang sa kung paano sila naiiba sa mga sanggunian sa phantom. Tara na! :) Upang magsimula, bakit kailangan natin ng mga sanggunian ng phantom? Tulad ng alam mo, inilalabas ng garbage collector (gc) ang memorya na ginagamit ng mga hindi kinakailangang Java object. Tinatanggal ng kolektor ang isang bagay sa dalawang "pass". Sa unang pass, tumitingin lamang ito sa mga bagay, at, kung kinakailangan, minarkahan ang mga ito bilang "hindi kailangan" (ibig sabihin, "matatanggal"). Kung angfinalize()ang pamamaraan ay na-override para sa bagay, ito ay tinatawag. O baka hindi ito tinatawag — depende lang ang lahat kung swerte ka. Malamang na naaalala mo na finalize()pabagu-bago :) Sa pangalawang pass ng basurero, ang bagay ay tinanggal at ang memorya ay napalaya. Ang hindi mahuhulaan na pag-uugali ng kolektor ng basura ay lumilikha ng ilang mga problema para sa atin. Hindi natin alam kung kailan talaga magsisimulang tumakbo ang tagakolekta ng basura. Hindi namin alam kung ang finalize()pamamaraan ay tatawagin. Dagdag pa, ang isang malakas na sanggunian sa isang bagay ay maaaring malikha habang ang finalize()pamamaraan nito ay isinasagawa, kung saan ang bagay ay hindi matatanggal. Para sa mga programang nangangailangan ng mabibigat na memorya, madali itong humantong sa isang OutOfMemoryError. Ang lahat ng ito ay nagtutulak sa amin na gumamit ng mga sanggunian sa phantom. Ang katotohanan ay binabago nito ang pag-uugali ng kolektor ng basura. Kung ang object ay may mga phantom reference lamang, kung gayon:
  • ang pamamaraan ng finalize() ay tinatawag (kung ito ay na-override)

  • kung walang magbabago kapag natapos na ang finalize() na paraan at maaari pa ring tanggalin ang object, ang phantom reference sa object ay ilalagay sa isang espesyal na queue: ReferenceQueue .

Ang pinakamahalagang bagay na dapat maunawaan kapag nagtatrabaho sa mga sanggunian ng phantom ay ang bagay ay hindi natatanggal sa memorya hanggang sa ang sanggunian ng phantom ay nasa pila na ito. Matatanggal lamang ito pagkatapos na tawagin ang clear() na paraan sa phantom reference. Tingnan natin ang isang halimbawa. Una, gagawa kami ng klase ng pagsubok na mag-iimbak ng ilang uri ng data.
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");
   }
}
Kapag gumawa kami ng mga bagay, sadyang bibigyan namin sila ng mabigat na "load" (sa pamamagitan ng pagdaragdag ng 50 milyong "x" na character sa bawat bagay) upang makakuha ng mas maraming memorya. Bilang karagdagan, ine-override namin ang finalize() na paraan upang makita na ito ay tumatakbo. Susunod, kailangan namin ng isang klase na magmamana mula sa PhantomReference . Bakit kailangan natin ng ganitong klase? Diretso lang lahat. Ito ay magpapahintulot sa amin na magdagdag ng karagdagang lohika sa clear() na paraan upang ma-verify na ang phantom reference ay talagang na-clear (na nangangahulugang ang bagay ay tinanggal na).
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();
   }
}
Susunod, kailangan namin ng hiwalay na thread na maghihintay para sa tagakolekta ng basura na gawin ang trabaho nito, at lilitaw ang mga phantom link sa aming ReferenceQueue . Sa sandaling mapunta ang naturang reference sa queue, ang cleanup() method ay tinatawag dito:
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();
   }
}
At sa wakas, kailangan namin ang pangunahing() na pamamaraan, na ilalagay namin ito sa isang hiwalay na Pangunahing klase. Sa paraang iyon, gagawa kami ng isang TestClass object, isang phantom reference dito, at isang queue para sa phantom reference. Pagkatapos nito, tatawagan namin ang tagakolekta ng basura at tingnan kung ano ang mangyayari :)
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();
   }
}
Output ng console:
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!
Ano ang nakikita natin dito? Nangyari ang lahat ayon sa plano namin! Ang pamamaraan ng finalize() ng aming object ay na-override at tinawag ito habang tumatakbo ang basurero. Susunod, ang phantom reference ay inilagay sa ReferenceQueue . Habang naroon, tinawag ang clear() na pamamaraan nito (kung saan tinawag namin ang cleanup() upang mag-output sa console). Sa wakas, ang bagay ay tinanggal mula sa memorya. Ngayon ay nakikita mo nang eksakto kung paano ito gumagana :) Siyempre, hindi mo kailangang kabisaduhin ang lahat ng teorya tungkol sa mga sanggunian ng phantom. Ngunit ito ay magiging mabuti kung tandaan mo ang hindi bababa sa mga pangunahing punto. Una, ito ang pinakamahinang mga sanggunian sa lahat. Naglalaro lamang ang mga ito kapag walang ibang reference sa bagay na natitira. Ang listahan ng mga sanggunian na ibinigay namin sa itaas ay pinagsunod-sunod sa pababang pagkakasunud-sunod mula sa pinakamalakas hanggang sa pinakamahina: StrongReference -> SoftReference -> WeakReference -> PhantomReference Ang isang phantom reference ay pumapasok lamang sa labanan kapag walang malakas, malambot, o mahinang reference sa aming object : ) Pangalawa, ang get() method ay palaging nagbabalik ng null para sa isang phantom reference. Narito ang isang simpleng halimbawa kung saan gumagawa kami ng tatlong magkakaibang uri ng mga sanggunian para sa tatlong magkakaibang uri ng mga kotse:
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());

   }
}
Output ng console:
Sedan@4554617c
HybridAuto@74a14482
null
Ang get() method ay nagbalik ng ganap na ordinaryong mga bagay para sa malambot at mahinang mga sanggunian, ngunit ito ay nagbalik ng null para sa phantom reference. Pangatlo, ang mga phantom reference ay pangunahing ginagamit sa mga kumplikadong pamamaraan para sa pagtanggal ng mga bagay mula sa memorya. Ayan yun! :) Iyan ang nagtatapos sa ating aralin ngayon. Ngunit hindi ka maaaring pumunta malayo sa teorya lamang, kaya oras na upang bumalik sa paglutas ng mga gawain! :)
Mga komento
  • Sikat
  • Bago
  • Luma
Dapat kang naka-sign in upang mag-iwan ng komento
Wala pang komento ang page na ito