betacode

Руководство Java WeakReference

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

1. WeakReference

Класс 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()

2. Primitive Inner Object

Примитивное значение не является ссылкой, хотя его можно записать как ссылку, поэтому, если оно завернуто в 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

3. Non-Primitive Inner Object

Если объект создан оператором "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, посетители могут оставаться и уходить только в том случае, если в ресторане больше нет свободных столов или количество свободных столов меньше безопасного значения.

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

Создайте объект 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

5. Complex example

Далее нам нужен более сложный пример. В этом примере объекты 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

Java Basic

Show More