openplanning

Hướng dẫn và ví dụ Java WeakReference

  1. WeakReference
  2. Primitive Inner Object
  3. Non-Primitive Inner Object
  4. WeakReference(T, ReferenceQueue<? super T>)
  5. Complex example

1. WeakReference

Lớp java.lang.ref.WeakReference được sử dụng để tạo ra một đối tượng bao bọc (wrap) một đối tượng khác - innerObject. Đối tượng mà nó bao bọc có thể bị Garbage Collector (GC) (Trình gom rác) loại bỏ ra khỏi bộ nhớ nếu nó không còn được sử dụng tại một nơi nào khác mạnh hơn GC.
AnyObject.java
package org.o7planning.beans;

public class AnyObject {
    private String val;
    public AnyObject(String val) {
        this.val = val;
    }
    public String getVal() {
        return this.val;
    }
}
Để dễ hiểu, hãy xem đoạn code dưới đây:
AnyObject innerObject = new AnyObject("Obj1");

WeakReference weakRef = new WeakReference(innerObject);
Trong đoạn code trên chúng ta có đối tượng innerObject, nó được sử dụng như một tham số để tạo ra đối tượng weakRef, hay nói cách innerObject đang được sử dụng bởi weakRef.
Theo suy nghĩ thông thường, nếu một đối tượng đang được sử dụng tại một nơi nào đó có nghĩa là nó đang có ích và không thể bị loại bỏ ra khỏi bộ nhớ. Tuy nhiên, WeakReference là một lớp đặc biệt, nó được coi là yếu hơn so với Garbage Collector (GC) (trình gom rác). Đối tượng được gói bên trong một WeakReference vẫn có thể bị GC loại bỏ ra khỏi bộ nhớ nếu nó không còn được sử dụng tại một nơi nào khác mạnh hơn GC.
WeakReference_obj_ex1.java
package org.o7planning.weakreference.ex;

import java.lang.ref.WeakReference;

import org.o7planning.beans.AnyObject;

public class WeakReference_obj_ex1 {

    public static void main(String[] args) throws InterruptedException {
        // Create innerObject reference points to AnyObject("Obj1").
        AnyObject innerObject = new AnyObject("Obj1");
        // Create WeakReference object using innerObject reference.
        WeakReference<AnyObject> weakRef = new WeakReference<AnyObject>(innerObject);
        
        System.out.println("weakRef.get(): " + weakRef.get());
        
        // Set innerObject reference to null (Points to null).
        innerObject = null;

        System.out.println("\nCall System.gc().\n");
        System.gc();
        Thread.sleep(3000);
        
        System.out.println("weakRef.get(): " + weakRef.get());
    }
}
Output:
weakRef.get(): org.o7planning.beans.AnyObject@5e91993f

Call System.gc().

weakRef.get(): null
Trong ví dụ trên chúng ta gọi phương thức System.gc() để yêu cầu Garbage Collector hoạt động, yêu cầu này không có tác dụng ngay lập tức. Về cơ bản, GC là một bộ máy tinh vi và phức tạp nó hoạt động một cách tự động và bạn chỉ có thể can thiệp vào nó một cách hạn chế.
Ví dụ tiếp theo, chúng ta sẽ không chủ động gọi phương thức System.gc(), nhưng GC vẫn sẽ loại bỏ đối tượng được gói bên trong WeakReference sau một thời gian nếu nó không còn được sử dụng tại một nơi nào khác mạnh hơn GC.
WeakReference_obj_ex2.java
package org.o7planning.weakreference.ex;

import java.lang.ref.WeakReference;

import org.o7planning.beans.AnyObject;

public class WeakReference_obj_ex2 {

    public static void main(String[] args) throws InterruptedException {
         // Create innerObject reference points to AnyObject("Obj1").
        AnyObject innerObject = new AnyObject("Obj1");
        // Create WeakReference object using innerObject reference.
        WeakReference<AnyObject> weakRef = new WeakReference<AnyObject>(innerObject);
        
        System.out.println("weakRef.get(): " + weakRef.get());

        int i = 0;
        while(true)  {
            AnyObject innerObj = weakRef.get();
            if(innerObj == null)  {
                System.out.println("Inner object is removed by Garbage Collector");
                System.out.println("weakRef.get(): " + innerObj);
                break;
            }
            i++;
            System.out.println(i+ " weakRef.get(): " + innerObj);
        }
    }
}
Output:
weakRef.get(): org.o7planning.beans.AnyObject@5e91993f
1 weakRef.get(): org.o7planning.beans.AnyObject@5e91993f
2 weakRef.get(): org.o7planning.beans.AnyObject@5e91993f

.....

283516 weakRef.get(): org.o7planning.beans.AnyObject@5e91993f
283517 weakRef.get(): org.o7planning.beans.AnyObject@5e91993f
283518 weakRef.get(): org.o7planning.beans.AnyObject@5e91993f
Inner object is removed by Garbage Collector
weakRef.get(): null
WeakReference constructors
WeakReference(T referent)

WeakReference(T referent, ReferenceQueue<? super T> q)
Tất cả các phương thức của WeakReference được thừa kế từ lớp cha.
// Methods inherited from parent.
public T get()  
public void clear()  
public boolean isEnqueued()  
public boolean enqueue()

2. Primitive Inner Object

Một giá trị nguyên thuỷ không phải là một tham chiếu mặc dù nó có thể được viết giống như một tham chiếu, vì vậy nếu nó được gói bên trong một WeakReference nó sẽ không bị GC loại bỏ ra khỏi bộ nhớ.
Integer innerObj1 = 1000;
Double innerObj2 = 2000.2;
String innerObj3 = "SomeString";
Ví dụ:
WeakReference_primitive_ex1.java
package org.o7planning.weakreference.ex;

import java.lang.ref.WeakReference;

public class WeakReference_primitive_ex1 {

    public static void main(String[] args) throws InterruptedException {
        Integer innerObj1 = 100;
        String  innerObj2 = "SomeString";
        
        WeakReference<Integer> weakRef1 = new WeakReference<Integer>(innerObj1);
        WeakReference<String> weakRef2 = new WeakReference<String>(innerObj2);
        
        System.out.println("weakRef1.get(): "  + weakRef1.get());
        System.out.println("weakRef2.get(): "  + weakRef2.get());
        
        // Points to null.
        innerObj1 = null;
        innerObj2 = null;
        
        System.out.println("\n--- Call System.gc(): ---\n");
        // Call GC:
         System.gc();
        Thread.sleep(3000);
        
        
        System.out.println("weakRef1.get(): "  + weakRef1.get());
        System.out.println("weakRef2.get(): "  + weakRef2.get());
    }
}
Output:
weakRef1.get(): 100
weakRef2.get(): SomeString

--- Call System.gc(): ---

weakRef1.get(): 100
weakRef2.get(): SomeString

3. Non-Primitive Inner Object

Nếu một đối tượng được tạo ra bởi toán tử "new" và được gói bên trong một WeakReference nó sẽ bị GC loại bỏ khỏi bộ nhớ nếu nó không còn được sử dụng ở một nơi nào khác mạnh hơn GC.
AnyObject innerObj1 = new AnyObject("Obj1");
String innerObj2 = new String("Obj2");
Integer innerObj3 = new Integer(1000);
String innerObj4 = new String("Obj4");

WeakReference<AnyObject> weakRef = new WeakReference<AnyObject>(innerObj1);
Đối tượng được gói bên trong WeakReference đóng vai trò như một thực khách trong một nhà hàng. Khi thực khách ăn xong họ sẵn sàng rời khỏi bàn kể cả khi tại thời điểm đó nhà hàng có rất nhiều bàn trống. SoftReference hơi khác một chút so với WeakReference, thực khách có thể ngồi lại và chỉ rời đi nếu nhà hàng không còn bàn trống hoặc quá số bàn trống nhỏ hơn một giá trị an toàn.

4. WeakReference(T, ReferenceQueue<? super T>)

Tạo một đối tượng WeakReference bao bọc đối tượng innerObject. Nếu innerObject bị GC loại bỏ khỏi bộ nhớ đối tượng WeakReference này sẽ được thêm vào queue.
WeakReference(T innerObject, ReferenceQueue<? super T> queue)
Ví dụ:
WeakReference_c2_ex1.java
package org.o7planning.weakreference.ex;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;

import org.o7planning.beans.AnyObject;

public class WeakReference_c2_ex1 {

    public static void main(String[] args) throws InterruptedException {

        AnyObject myAnyObject1 = new AnyObject("Obj1");
        AnyObject myAnyObject2 = new AnyObject("Obj2");

        ReferenceQueue<AnyObject> queue = new ReferenceQueue<AnyObject>();
        //
        WeakReference<AnyObject> weakRef1 = new WeakReference<AnyObject>(myAnyObject1, queue);
        WeakReference<AnyObject> weakRef2 = new WeakReference<AnyObject>(myAnyObject2, queue);

        System.out.println("weakRef1: " + weakRef1);
        System.out.println("weakRef2: " + weakRef2);
        System.out.println("weakRef1.get(): " + weakRef1.get());
        System.out.println("weakRef2.get(): " + weakRef2.get());

        // Set myAnyObject1 reference to null (Points to null).
        myAnyObject1 = null;

        System.out.println("\nCall System.gc().\n");
        System.gc();
        Thread.sleep(3000);

        // myAnyObject2 is still used.
        System.out.println("myAnyObject2: " + myAnyObject2);

        System.out.println("weakRef1.get(): " + weakRef1.get());
        System.out.println("weakRef2.get(): " + weakRef2.get());

        Reference<? extends AnyObject> removed = null;
        while ((removed = queue.poll()) != null) {
            System.out.println("removed: " + removed);
        }
    }
}
Output:
weakRef1: java.lang.ref.WeakReference@5e91993f
weakRef2: java.lang.ref.WeakReference@156643d4
weakRef1.get(): org.o7planning.beans.AnyObject@123a439b
weakRef2.get(): org.o7planning.beans.AnyObject@7de26db8

Call System.gc().

myAnyObject2: org.o7planning.beans.AnyObject@7de26db8
weakRef1.get(): null
weakRef2.get(): org.o7planning.beans.AnyObject@7de26db8
removed: java.lang.ref.WeakReference@5e91993f

5. Complex example

Tiếp theo, chúng ta cần một ví dụ phức tạp hơn. Trong ví dụ này các đối tượng Employee được thêm vào một Company. Và một đối tượng List chứa danh sách các tham chiếu yếu tới từng đối tượng Employee. Chừng nào Company còn lưu trữ các đối tượng Employee chúng sẽ không bị GC loại bỏ ra khỏi bộ nhớ.
WeakReference_ex1.java
package org.o7planning.weakreference.ex;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class WeakReference_ex1 {

    public static void main(String[] args) throws InterruptedException {
        Employee tom = new Employee("Tom");
        Employee jerry = new Employee("Jerry");
        Employee donald = new Employee("Donald");

        Employee[] employees = new Employee[] { tom, jerry, donald };

        Company company = new Company();

        ReferenceQueue<Employee> queue = new ReferenceQueue<>();
        List<WeakReference<Employee>> empListWeak = new ArrayList<WeakReference<Employee>>();

        for (int i = 0; i < employees.length; i++) {
            company.addEmployee(employees[i]);

            empListWeak.add(new WeakReference<Employee>(employees[i], queue));
        }
        // Free up the array.
        employees = null;

        System.out.println("Queue's polling returns null? " + (queue.poll() == null));

        for (WeakReference<Employee> wref : empListWeak) {
            System.out.println("wref.get().getFullName(): " + wref.get().getFullName());
        }

        //
        System.out.println("\n--- Remove some employees from company: ---\n");
        company.removeEmployee(tom);
        company.removeEmployee(jerry);
        tom = null;
        jerry = null;
        donald = null; // 'donald' is still used in company.

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

        Reference<? extends Employee> wref = null;
        System.out.println("Poll weak emp references garbage collected");
        while ((wref = queue.poll()) != null) {
            System.out.println("WeakReference of Emp removed from queue: " + wref);

        }
        System.out.println("done");
    }
}

class Employee {
   private String fullName;
   public Employee(String fullName)  {
       this.fullName = fullName;
   }
   public String getFullName()  {
       return this.fullName;
   }
}


class Company {
    private Set<Employee> employees = new HashSet<Employee>();

    public void addEmployee(Employee employee) {
        this.employees.add(employee);
    }

    public void removeEmployee(Employee employee) {
        employees.remove(employee);
    }
}
Output:
Queue's polling returns null? true
wref.get().getFullName(): Tom
wref.get().getFullName(): Jerry
wref.get().getFullName(): Donald

--- Remove some employees from company: ---

Poll weak emp references garbage collected
WeakReference of Emp removed from queue: java.lang.ref.WeakReference@1175e2db
WeakReference of Emp removed from queue: java.lang.ref.WeakReference@36aa7bc2
done

Java cơ bản

Show More