2014-02-07 2 views
0

В одной программе мне нужно хранить слабые ссылки в определенном хранилище (встроенная база данных Prolog на самом деле). Чтобы упростить объяснение, такой механизм хранения можно рассматривать (в контексте этого вопроса) как набор слабых ссылок.Очистка ресурсов, связанных со слабым ссылкой

Мне нужно гарантировать, что слабые ссылки будут удалены из механизма хранения, как только ссылка будет восстановлена. Другими словами, не должно быть возможности получить доступ к слабой ссылке с движка, если его метод get() уже возвращает значение null.

В настоящее время я реализовал это с помощью ReferenceQueue.

Следующий код расширяет слабую ссылку с помощью добавления cleanUp() метода (который вызывает задачу очистки, которая удаляет слабую ссылку от двигателя):

public class MyWeakRef<REF_TYPE> extends WeakReference<REF_TYPE> { 

    MyWeakRef(REF_TYPE referent, ReferenceQueue<REF_TYPE> referenceQueue, Runnable cleaningTask, ...) { 
     super(referent, referenceQueue); 
     this.cleaningTask = cleaningTask; 
     ... 
    } 

    void cleanUp() { 
     cleaningTask.run();  
    } 
    ... 
} 

Код ниже показывает, как ссылки очищено в отдельном потоке, который принимает восстановленные ссылки из ReferenceQueue и вызывает их cleanUp() метода:

public class WeakReferencesCleaner extends Thread { 

    private static WeakReferencesCleaner referencesCleaner = new WeakReferencesCleaner(new ReferenceQueue<Object>()); 

    public static WeakReferencesCleaner getWeakReferencesCleaner() { 
     return referencesCleaner; 
    } 

    public synchronized static void startWeakReferencesCleaner() { 
     if(!referencesCleaner.isAlive()) 
      referencesCleaner.start(); 
} 

    private ReferenceQueue<?> referenceQueue; 

    public WeakReferencesCleaner(ReferenceQueue<?> referenceQueue, int priority) { 
     this.referenceQueue = referenceQueue; 
     this.setDaemon(true); 
    } 

    public ReferenceQueue<?> getReferenceQueue() { 
     return referenceQueue; 
    } 

    @Override 
    public void run() { 
     while(true) { 
      try { 
       MyWeakRef<?> ref = (JTermRef<?>) referenceQueue.remove(); 
       try { 
        ref.cleanUp(); 
       } catch(Exception e) { 
     ... 
      } 
       } catch (InterruptedException e) {} 
      } 
    } 
} 

Хотя в моих тестах это работает отлично, я узнал следующий в документации WeakReference класса:

Предположим, что сборщик мусора определяет в какой-то момент в времени, что объект является слабо доступным. В то время он будет атомарно очистить все слабые ссылки на этот объект ... При этом время или в какое-то позднее время оно проведет в очередь тех недавно очищенных слабых ссылок, которые зарегистрированы в контрольных очередях.

Таким образом, между временем, ссылка недействительна и метод cleanUp() выполняется другой поток может запросить двигатель и до сих пор найти аннулированную ссылку.

Мой вопрос: Как я могу гарантировать в многопоточном контексте, что мой недействительный отзыв никогда не возвращается моим движком?

+0

короткий ответ, вы не можете. вам нужно будет изменить свои требования или использовать другое средство. – jtahlborn

+0

Если вам нужны предложения для альтернативных решений, вам нужно будет предоставить более подробную информацию о проблеме, которую вы пытаетесь решить. – jtahlborn

+0

привет @jtahlborn, что вы имеете в виду, используя «другое средство»? – Sergio

ответ

0

Вы должны отрегулировать свои требования. Код, относящийся к List от WeakReference s, является достаточно низким, чтобы справиться с тем, что метод может возвращать null. Этот код, относящийся к List, отвечает за предоставление API более высокого уровня, который не показывает ни WeakReference, ни ложных значений null. Класс WeakHashMap дает синюю печать такой конструкции. Код с использованием WeakHashMap не должен иметь дело с возможной взаимной сборкой мусора. Метод get()WeakHashMap делает внутренне.

Обратите внимание, что даже если не было времени между сбором и хранением, не было никакой гарантии, что вы не увидите null значений из метода get(). Дело в том, что вы очищаетесь в другом потоке, поэтому в любом случае нет гарантированного времени. A Reference, находящийся в очереди, не подразумевает, что ваш поток очистки, опросивший эту очередь, немедленно получит процессорное время.Это будет зависеть от того, будет ли поток потока потока выполняться своевременно до того, как поток, читающий List, сможет получить затронутый элемент.

Смежные вопросы