为了账号安全,请及时绑定邮箱和手机立即绑定

覆盖同步锁中使用的变量是否会阻止其垃圾收集?

覆盖同步锁中使用的变量是否会阻止其垃圾收集?

侃侃尔雅 2022-06-04 16:58:02
我在我的服务中有一个缓存作为成员变量,我正在创建一个通过 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 回答

?
肥皂起泡泡

TA贡献1829条经验 获得超6个赞

通过查看为类似情况生成的字节码,我们可以看到锁定字段的对象地址被复制并用于获取和释放锁。所以原始锁定对象用于锁定。


在同步块内用新对象更改锁定字段后,另一个线程可以获取新对象的锁定,并可以进入同步代码块。像这样使用同步,不提供线程之间的同步。您应该使用另一个对象进行锁定。(如最终对象 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

    .....


查看完整回答
反对 回复 2022-06-04
  • 1 回答
  • 0 关注
  • 145 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号