加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

如何在Groovy中构建可重新初始化的惰性属性?

发布时间:2020-12-14 16:23:02 所属栏目:大数据 来源:网络整理
导读:这就是我想做的事情: class MyObject { @Lazy volatile String test = { //initalize with network access }()}def my = new MyObject()println my.test//Should clear the property but throws groovy.lang.ReadOnlyPropertyExceptionmy.test = null //Sho
这就是我想做的事情:

class MyObject {
    @Lazy volatile String test =  {
        //initalize with network access
    }()
}

def my = new MyObject()
println my.test

//Should clear the property but throws groovy.lang.ReadOnlyPropertyException
my.test = null 

//Should invoke a new initialization
println my.test

不幸的是,惰性字段是Groovy中的只读字段,清除属性会导致异常.

知道如何重新实现惰性字段,而无需重新实现@Lazy注释提供的双重检查逻辑吗?

更新:

考虑soft = true(从第一个答案开始)让我进行了一些测试:

class MyObject {
    @Lazy() volatile String test =  {
        //initalize with network access
        println 'init'
        Thread.sleep(1000)
        'test'
    }()
}

def my = new MyObject()
//my.test = null 
10.times { zahl ->
    Thread.start {println "$zahl: $my.test"}
}

大约1秒后,我的Groovy控制台上会有以下输出:

init
0: test
7: test
6: test
1: test
8: test
4: test
9: test
3: test
5: test
2: test

这是预期的(和想要的).现在我添加soft = true,结果发生了显着变化,需要10秒钟:

init
init
0: test
init
9: test
init
8: test
init
7: test
init
6: test
init
5: test
init
4: test
init
3: test
init
2: test
1: test

也许我正在测试错误或soft = true完全破坏了缓存效果.有任何想法吗?

解决方法

你不能使用软 attribute of Lazy,即:

class MyObject {
  @Lazy( soft=true ) volatile String test =  {
    //initalize with network access
  }()
}

编辑

使用soft = true,注释会生成一个setter和一个getter,如下所示:

private volatile java.lang.ref.SoftReference $test 

public java.lang.String getTest() {
    java.lang.String res = $test?.get()
    if ( res != null) {
        return res 
    } else {
        synchronized ( this ) {
            if ( res != null) {
                return res 
            } else {
                res = { 
                }.call()
                $test = new java.lang.ref.SoftReference( res )
                return res 
            }
        }
    }
}

public void setTest(java.lang.String value) {
    if ( value != null) {
        $test = new java.lang.ref.SoftReference( value )
    } else {
        $test = null
    }
}

如果没有soft = true,你就不会得到一个setter

private volatile java.lang.String $test 

public java.lang.String getTest() {
    java.lang.Object $test_local = $test 
    if ( $test_local != null) {
        return $test_local 
    } else {
        synchronized ( this ) {
            if ( $test != null) {
                return $test 
            } else {
                return $test = { 
                }.call()
            }
        }
    }
}

所以变量是只读的.目前还不确定这是故意还是使用soft = true的副作用虽然…

编辑#2

这看起来可能是使用soft = true实现Lazy的一个错误

如果我们将getter更改为:

public java.lang.String getTest() {
    java.lang.String res = $test?.get()
    if( res != null ) {
      return res 
    } else {
      synchronized( this ) {
        // Get the reference again rather than just check the existing res
        res = $test?.get()
        if( res != null ) {
          return res
        } else {
          res = { 
            println 'init'
            Thread.sleep(1000)
            'test'
          }.call()
          $test = new java.lang.ref.SoftReference<String>( res )
          return res 
        }
      }
    }
  }

我认为它正在运作……我将开发一个修正错误

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读