Basic-WeakReference, weakreference
I. Overview
To better understand the principles of WeakHashMap, we need to first understand the functions and implementation principles of WeakReference. Java has a special package, java. lang. ref, which defines several references that we usually call, specifically as follows:
Reference: a basic Reference class. It is an abstract class that defines some basic methods for Reference.
SoftReference: soft reference. Soft reference objects are recycled before the application displays OOM.
WeakReference: weak reference. If an object is associated with a weak reference, the garbage collector recycles it.
PhantomReference.
ReferenceQueue: reference the queue. The Garbage Collector puts recycled queues in this queue.
In addition to the above three types of references, there is also a class of references called strong references. Strong references are what we usually call references. Therefore, java does not define a reference class separately.
This article focuses on the use of WeakReference and its implementation principles.
Ii. Example of WeakReference
Before introducing its implementation principles, let's take a look at its usage. According to the definition of WeakReference, if an object is referenced only by weak references, this object is weakly accessible, weak reachable objects are recycled during garbage collection.
This may be difficult to understand, so we will use an example to illustrate the effect of its use. The Code is as follows:
public class TestWeakReference { public static void main(String[] args) throws Exception{ UserInfo userInfo = new UserInfo("Jim Green"); UserInfo anotherUser = userInfo; WeakReference<UserInfo> weakUser = new WeakReference<>(userInfo); System.out.println("\nBefore userInfo is null"); System.out.println("strong ref:" + anotherUser); System.out.println("weak ref:" + weakUser.get()); userInfo = null; System.gc(); System.out.println("\nAfter userInfo is null"); System.out.println("strong ref:" + anotherUser); System.out.println("weak ref:" + weakUser.get()); anotherUser = new UserInfo("Jim White"); System.gc(); System.out.println("\nAfter anotherUser is changed"); System.out.println("strong ref:" + anotherUser); System.out.println("weak ref:" + weakUser.get()); }}class UserInfo { private String name; public UserInfo(String name){ this.name = name; } @Override public String toString() { return "Name is " + name; }}
The running result of the above Code is as follows:
From the above results, we can see that at the beginning, all three references point to the same user object Jim Green, and then we set the original reference to null for garbage collection, however, since there is another strong reference pointing to this Jim Green, this user object will not be recycled. Finally, if there is no strong reference, it will be directed to it and then garbage collection will be performed, jim Green is recycled.
This result also confirms the role of WeakReference. If the object to which it points is not pointed by any strong reference, the object can be recycled.
Next we will demonstrate this process in the form of a legend.
Iii. Implementation Principles of WeakReference
We have demonstrated in detail how to use it. Next, let's talk about its main implementation.
1. UML diagram
The relationship between WeakReference, Reference, and ReferenceQueue is as follows:
The main attributes and methods of these three classes are listed. Among them, WeakReference is an abstract class, but provides a basic function required for reference. WeakReference is just a simple inheritance and does not implement any extended functions.
Reference has two constructor methods, with and without Queues:
Reference(T referent) { this(referent, null); } Reference(T referent, ReferenceQueue<? super T> queue) { this.referent = referent; this.queue = (queue == null) ? ReferenceQueue.NULL : queue; }
It can be seen that the referent property stores the objects it references, while the queue field is optional. As mentioned above, the function of the queue saves the reference of the object to be recycled, the garbage collector is responsible for adding the content to it, but if it is not provided, there is no such process.
2. Status description:
According to the class description, there are four States to reference:
Active: This is the initial state after the reference is created. If the accessibility of the object referenced by the reference object changes, the status of the reference itself changes to Pending or Inactive, it depends on whether the reference uses a queue during creation. If a queue is used, the status will be converted to Pending; otherwise, the status will be changed to Inactive.
Pending: it is converted from Active state. Reference in this state is in a public pending queue, waiting to be added to the queue. The processing of pending queues is monitored and processed by a daemon with a higher priority in real time. If the reference does not use queue during initialization, it will not be added to the pending queue, nor can it be added to the queue.
Enqueued: converted from Pending. If the reference in the pending list is correctly added to the queue, the referenced state is enqueued. If the reference is removed from the queue, then it will become InActive. Similarly, this premise is that the queue needs to be specified during the construction.
InActive: in the final state, the reference object in this state has no effect, and the State will not change.
These four States are just a description. In fact, the Reference object does not have any status fields, but as a node in the queue, it has a next field. When the status is Active, its next is null, and when it is another State, next must not be null, but point to the next reference in the queue. If it is itself the last element in the queue, next points to itself.
3. Principles:
After introducing the structure and status descriptions, we will analyze the implementation. There are two situations:
1) queue is not used during construction:
This situation is relatively simple. State conversion only involves Active and InActive operations, and does not involve queue operations. When the referenced object does not have any other strong references, the garbage collector recycles the object, the status should also change to InActive. note that, in this way, get () will directly return null.
2) The constructor uses queue:
This situation is complicated. When the referenced object has no other strong references, the garbage collector will first add it to the pending queue, the Reference process processes the referenced objects in the pending queue through a common daemon thread and adds them to the queue.
The processing logic of this process is as follows:
1 private static class ReferenceHandler extends Thread {2 3 ReferenceHandler (ThreadGroup g, String name) {4 super (g, name); 5} 6 7 public void run () {8 for (;) {9 10 Reference r; 11 synchronized (lock) {12 if (pending! = Null) {13 r = pending; // obtain an element 14 Reference rn = r. next; // find the next referenced object in the queue 15 pending = (rn = r )? Null: rn; // if it is the last element, the pending queue is left empty 16 r. next = r; // change its next17} else {18 try {19 lock. wait (); // wait 20} catch (InterruptedException x) {} 21 continue; 22} 23} 24 25 // Fast path for cleaners26 if (r instanceof Cleaner) {27 (Cleaner) r ). clean (); 28 continue; 29} 30 31 ReferenceQueue q = r. queue; 32 if (q! = ReferenceQueue. NULL) q. enqueue (r); // call the queuing Method 33} 34} 35}
The above method will always process the pending queue until it is null and then it will be in the wait status. The problem arises. When the pending queue is not empty again, this thread needs to be awakened. Who will add a reference object to the pending queue and perform the wake-up operation?The answer is that it is called by the garbage collector when the referenced object is recycled..
Therefore, the garbage collector converts the referenced object from Active to Pending, and the thread of the referenced object converts the referenced object from Pending to Enqueued.
Next, let's take a look at the handling process of the ReferenceQueue team:
1 boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */ 2 synchronized (r) { 3 if (r.queue == ENQUEUED) return false; 4 synchronized (lock) { 5 r.queue = ENQUEUED; 6 r.next = (head == null) ? r : head; 7 head = r; 8 queueLength++; 9 if (r instanceof FinalReference) {10 sun.misc.VM.addFinalRefCount(1);11 }12 lock.notifyAll();13 return true;14 }15 }16 }
From its implementation logic, we can see that each time you join a queue, you can start from the ground up. After you join the queue, you can update its queue attribute to prevent multiple queues.
There is also the team-out function, and this will not be analyzed.
We have finished introducing the queue, but the garbage collector does not operate this queue. What is the purpose of this queue? The following is a description of JDK:
"When creating a reference objectReference queue RegisterAn appropriate reference object, the program can request to be notified when the object accessibility changes. When the Garbage Collector determines that the accessibility of the reference has been changed to a time after the reference type value, it will add the reference to the relevant queue. In this case, the reference is consideredAdded to the queue. By polling or blocking, the program can remove the reference from the queue until the reference is obtained. The reference queue isReferenceQueueClass ."
Therefore, this queue is provided for Application Notification. That is to say, the program can listen to this queue to learn which objects pointed to by weak references have been recycled, then the program can perform corresponding processing. For how to monitor the queue, refer to the pending queue Processing Method in the Reference class.
Iv. Summary
So far, we have made a complete introduction to the implementation methods of Reference and ReferenceQueue. The following is a summary:
1. WeakReference must be associated with another object when it is created. If the object has no other common (strong) reference, the object will be recycled by the garbage collector.
2. when defining a Reference, you can specify a ReferenceQueue queue. The queue is used to store Reference objects that have been recycled by the associated objects to be listened to by the application, however, the process is determined by the application itself.
3. WeakReference inherits from Reference, but does not provide extended functions.