Руководство Java WeakReference
View more Tutorials:


Класс java.lang.ref.WeakReference используется для создания объекта, который обертывает (wrap) другой объект - innerObject. Объект, который он обертывает, может быть удален из памяти by Garbage Collector (GC) (сборщиком мусора), если он больше не используется в другом месте, более сильном, чем 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;
}
}
Для удобства понимания см. code ниже:
AnyObject innerObject = new AnyObject("Obj1");
WeakReference weakRef = new WeakReference(innerObject);
В приведенном выше коде у нас есть объект innerObject, который используется в качестве параметра для создания объекта weakRef, или, другими словами, innerObject используется by weakRef.
В общем смысле, если объект где-то используется, он полезен и не может быть удален из памяти. Однако WeakReference - это особый класс, который считается более слабым, чем Garbage Collector (GC) (сборщик мусора). Объект, завернутый в WeakReference, все еще может быть удален из памяти GC, если он больше не используется в другом месте, более сильном, чем 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
В приведенном выше примере мы вызываем метод System.gc(), чтобы сообщить Garbage Collector о работе. Эта просьба не имеет немедленного действия. По сути, GC - это сложная машина, которая работает автоматически, и вы можете вмешиваться в нее только ограниченным образом.
В следующем примере мы не будем активно вызывать метод System.gc(), но GC все равно удалит объект, завернутый в WeakReference, через некоторое время, если он больше не используется в другом месте, более сильном, чем 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)
Все методы WeakReference наследуются от родительского класса.
// Methods inherited from parent.
public T get()
public void clear()
public boolean isEnqueued()
public boolean enqueue()
Примитивное значение не является ссылкой, хотя его можно записать как ссылку, поэтому, если оно завернуто в WeakReference, оно не будет удалено из памяти by GC.
Integer innerObj1 = 1000;
Double innerObj2 = 2000.2;
String innerObj3 = "SomeString";
Например:
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
Если объект создан оператором "new" и завернут в WeakReference, он будет удален из памяти by GC, если он больше не используется в другом месте, более сильном, чем 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);

Объект, завернутый в WeakReference, действует как посетители в ресторане. Когда посетители заканчивают есть, они готовы покинуть стол, даже если в это время в ресторане много пустых столов. SoftReference немного отличается от WeakReference, посетители могут оставаться и уходить только в том случае, если в ресторане больше нет свободных столов или количество свободных столов меньше безопасного значения.
Создайте объект WeakReference, который обертывает объект innerObject. Если innerObject удаляется из памяти by GC, этот объект WeakReference будет добавлен в queue.
WeakReference(T innerObject, ReferenceQueue<? super T> queue)
Например:
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
Далее нам нужен более сложный пример. В этом примере объекты Employee добавляются в Company. И объект List, содержащий список слабых ссылок на каждый объект Employee. Пока Company хранит объекты Employee, они не будут удалены из памяти by GC.
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