Перезаписывает ли переменная, используемая в синхронизированной блокировке, сборку мусора? - PullRequest
0 голосов
/ 04 февраля 2019

У меня есть кеш как переменная-член в моем сервисе, и я создаю метод для предоставления его через JMX MBean, чтобы я мог разорвать и воссоздать свой кэш vogon во время выполнения с новым временем истечения срока действия кеша:

public class CachedVogonService implements CachedVogonServiceMBean {

    private LoadingCache<String, Vogon> cache;
    private long expiryInSeconds;
    private VogonService service;

    public CachedVogonService(VogonService newService,
                                long newExpiryInSeconds) {
        this.expiryInSeconds = newExpiryInSeconds;
        this.service = newService;
        this.cache = createCache(newService, newExpiryInSeconds);
    }

    private LoadingCache<String, Vogon> createCache(
            VogonService newService,
            long expiryInSeconds) {
        return CacheBuilder.newBuilder()
                .refreshAfterWrite(expiryInSeconds, TimeUnit.SECONDS)
                .build(new VogonCacheLoader(
                        Executors.newCachedThreadPool(), newService));
    }

    /**
     * This is the method I am exposing in JMX
     */    
    @Override
    public void setExpiryInSeconds(long newExpiryInSeconds) {
        this.expiryInSeconds = newExpiryInSeconds;
        synchronized (this.cache) {
            this.cache = createCache(service, expiryInSeconds);
        }
    }

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

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

1 Ответ

0 голосов
/ 05 февраля 2019

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

После того как вы измените поле блокировки новым объектом внутри синхронизированного блока, другой поток может получить блокировку для нового объекта и войти в блок синхронизированного кода.Использование синхронизации, как это, не обеспечивает синхронизацию между потоками.Вы должны использовать другой объект для блокировки.(например, конечный объект cacheLock = new Object ())

Только для информационных целей этот вид использования не предотвращает сборку мусора.Поскольку упомянутые здесь адреса объектов находятся внутри стекового фрейма этого метода, как только метод завершит выполнение, стековый фрейм будет уничтожен, и ссылка на старый объект не останется.(Но не используйте синхронизированный таким образом.)

Вы можете проверить набор инструкций JVM здесь

public class SyncTest {

    private Long value;

    public static void main(String[] args) {
        new SyncTest().testLock();
    }

    public SyncTest() {
        value = new Long(1);
    }

    private void testLock() {
        synchronized (this.value) {
            this.value = new Long(15);
        }
    }
}

  private void testLock();
     0  aload_0 [this]
     1  getfield t1.SyncTest.value : java.lang.Long [27] // push value field to operand stack
     4  dup // duplicate value field push it to operand stack
     5  astore_1 // store the top of the operand stack at [1] of local variable array (which is the duplicated value field)
     6  monitorenter // aquire lock on top of the operand stack 
     7  aload_0 [this]
     8  new java.lang.Long [22]
    11  dup
    12  ldc2_w <Long 15> [31]
    15  invokespecial java.lang.Long(long) [24]
    18  putfield t1.SyncTest.value : java.lang.Long [27]
    21  aload_1 // load the [1] of local variable array to the operand stack (which is the duplicated value field previously stored)
    22  monitorexit // release the lock on top of the operand stack
    23  goto 29
    26  aload_1
    27  monitorexit
    .....
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...