Как протестировать WeakReference в потоке?

Рейтинг: 2Ответов: 1Опубликовано: 22.04.2015

Я хочу разобраться как работает WeakReference на простом примере. Есть подозрения что в моей программе WeakReference в отдельном потоке становится strong ссылкой.

Попытался сделать следующим образом:

public class TestWeak {

private static Object object;
private static WeakReference<Object> wr;
private static Runnable runnable = new Runnable() {
    @Override
    public void run() {
        try {
            Object object4 = object;
            System.out.println("Object4: " + object4);
            Object object5 = wr.get();
            System.out.println("Object5: " + object5);

            System.out.println("Setting object to null");
            object = null;
            System.out.println("Running Garbage Collection...");
            Runtime.getRuntime().gc(); // run GC to collect the object
            Thread.sleep( 1000 );
            System.out.println("Setting object4 to null");
            object4 = null;
            System.out.println("Running Garbage Collection...");
            Runtime.getRuntime().gc(); // run GC to collect the object  
            Thread.sleep( 1000 );
            System.out.println("Setting object5 to null");
            object5 = null;
            System.out.println("Running Garbage Collection...");
            Runtime.getRuntime().gc(); // run GC to collect the object              
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
};

public static void main(String[] args) throws InterruptedException {
    object = new Object();      
    // Create a new weak reference that refers to the given object and is registered with this queue.
    wr = new WeakReference<Object>(object); // , rq);
    System.out.println("Object: " + object);
    Object object2 = wr.get();
    System.out.println("Object2: " + object2);
    Object object3 = object2;
    System.out.println("Object3: " + object3);      
    // start a new thread that will remove all references of object     
    ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
    service.schedule(runnable, 2, TimeUnit.SECONDS);
    System.out.println("Wait ....");
    boolean flag = true;
    while (flag) {
        if (wr.get() == null) {
            System.out.println("Reference: " + wr);
            System.out.println("Object is no longer referenced.");
            flag = false;
        }                   
    }
    service.shutdown();     
}
}

Console:

Object: java.lang.Object@7852e922
Object2: java.lang.Object@7852e922
Object3: java.lang.Object@7852e922
Wait ....
Object4: java.lang.Object@7852e922
Object5: java.lang.Object@7852e922
Setting object to null
Running Garbage Collection...
Setting object4 to null
Running Garbage Collection...
Setting object5 to null
Running Garbage Collection...
Reference: java.lang.ref.WeakReference@3d4eac69
Object is no longer referenced.

Почему GC удаляет объект только после того как object5 (weak ссылка) устанавливается в null ?

UPDATE:

Если закомментировать эту строку:

// object5 = null;

Вы никогда не увидите в консоли:

Object is no longer referenced.

Наши заморские друзья говорят что GC работает как ему вздумается. https://stackoverflow.com/questions/29784793/java-weakreference-inside-thread

Но на мой взгляд приведенный пример никак не отражается на разной работе GC, а проблема заключается в неправильной работе/использовании WeakReference.

P.S. Так же пробовал параллельно переполнить память. Память переполнил, а в нужную строку в консоли так и не увидел.

Ответы

▲ 3Принят

Вы ошибаетесь, считая что object5 - это слабая ссылка на объект. object5 - это сильная ссылка. Слабая ссылка в вашей программе только одна - wr.