Hướng dẫn và ví dụ Java WeakReference
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
- Tùy biến trình biên dịch java xử lý Annotation của bạn (Annotation Processing Tool)
- Lập trình Java theo nhóm sử dụng Eclipse và SVN
- Hướng dẫn và ví dụ Java WeakReference
- Hướng dẫn và ví dụ Java PhantomReference
- Hướng dẫn nén và giải nén trong Java
- Cấu hình Eclipse để sử dụng JDK thay vì JRE
- Phương thức String.format() và printf() trong Java
- Cú pháp và các tính năng mới trong Java 5
- Cú pháp và các tính năng mới trong Java 8
- Hướng dẫn sử dụng biểu thức chính quy trong Java
- Hướng dẫn lập trình đa luồng trong Java - Java Multithreading
- Thư viện điều khiển các loại cơ sở dữ liệu khác nhau trong Java
- Hướng dẫn sử dụng Java JDBC kết nối cơ sở dữ liệu
- Lấy các giá trị của các cột tự động tăng khi Insert một bản ghi sử dụng JDBC
- Hướng dẫn và ví dụ Java Stream
- Functional Interface trong Java
- Giới thiệu về Raspberry Pi
- Hướng dẫn và ví dụ Java Predicate
- Abstract class và Interface trong Java
- Access modifier trong Java
- Hướng dẫn và ví dụ Java Enum
- Hướng dẫn và ví dụ Java Annotation
- So sánh và sắp xếp trong Java
- Hướng dẫn và ví dụ Java String, StringBuffer và StringBuilder
- Hướng dẫn xử lý ngoại lệ trong Java - Java Exception Handling
- Hướng dẫn và ví dụ Java Generics
- Thao tác với tập tin và thư mục trong Java
- Hướng dẫn và ví dụ Java BiPredicate
- Hướng dẫn và ví dụ Java Consumer
- Hướng dẫn và ví dụ Java BiConsumer
- Bắt đầu với Java cần những gì?
- Lịch sử của Java và sự khác biệt giữa Oracle JDK và OpenJDK
- Cài đặt Java trên Windows
- Cài đặt Java trên Ubuntu
- Cài đặt OpenJDK trên Ubuntu
- Cài đặt Eclipse
- Cài đặt Eclipse trên Ubuntu
- Học nhanh Java cho người mới bắt đầu
- Lịch sử của bit và byte trong khoa học máy tính
- Các kiểu dữ liệu trong Java
- Các toán tử Bitwise
- Câu lệnh rẽ nhánh (if else) trong Java
- Câu lệnh rẽ nhánh switch trong Java
- Vòng lặp trong Java
- Mảng (Array) trong Java
- JDK Javadoc định dạng CHM
- Thừa kế và đa hình trong Java
- Hướng dẫn và ví dụ Java Function
- Hướng dẫn và ví dụ Java BiFunction
- Ví dụ về Java encoding và decoding sử dụng Apache Base64
- Hướng dẫn và ví dụ Java Reflection
- Hướng dẫn gọi phương thức từ xa với Java RMI
- Hướng dẫn lập trình Java Socket
- Các nền tảng nào bạn nên chọn để lập trình ứng dụng Java Desktop?
- Hướng dẫn và ví dụ Java Commons IO
- Hướng dẫn và ví dụ Java Commons Email
- Hướng dẫn và ví dụ Java Commons Logging
- Tìm hiểu về Java System.identityHashCode, Object.hashCode và Object.equals
- Hướng dẫn và ví dụ Java SoftReference
- Hướng dẫn và ví dụ Java Supplier
- Lập trình Java hướng khía cạnh với AspectJ (AOP)
Show More
- Hướng dẫn lập trình Java Servlet/JSP
- Các hướng dẫn Java Collections Framework
- Java API cho HTML & XML
- Các hướng dẫn Java IO
- Các hướng dẫn Java Date Time
- Các hướng dẫn Spring Boot
- Các hướng dẫn Maven
- Các hướng dẫn Gradle
- Các hướng dẫn Java Web Services
- Các hướng dẫn lập trình Java SWT
- Các hướng dẫn lập trình JavaFX
- Các hướng dẫn Java Oracle ADF
- Các hướng dẫn Struts2 Framework
- Các hướng dẫn Spring Cloud