我一直在尝试做一个小型 Groovy 项目,并且想要一个ConcurrentLinkedHashSet,但 Java 没有提供。因此,我开始使用 Gpars 代理创建自己的代理来“保护”普通的 LinkedHashSet。然后我创建了我的包装类来保存代理,并将我的类上的方法委托给内部代理,就像这样(这个版本使用 methodMissing 作为委托方法)。我尝试了 Groovy interceptable/invokeMethod 并且可以让它工作
class ConcurrentLinkedHashSet /*implements GroovyInterceptable*/ {
Agent $concurrentHashSet = new Agent (new LinkedHashSet())
/*Object[] toArray () {
$concurrentHashSet.val.asType(LinkedHashSet).toArray()
}*/
def asType (Set) {
$concurrentHashSet.val
}
//set up delegation action to pass all methods to the agent to execute
def /*invokeMethod*/methodMissing (String name, args){
def result
System.out.println "methodMissing with $name and $args on $this"
System.out.println "agent value is : ${$concurrentHashSet.val.dump()} is instance of: ${$concurrentHashSet.getClass()}"
$concurrentHashSet {
System.out.println "\t\tconcHashSet methodMissing: it is of type ${it.getClass()} so called $it.invokemethod ($name, $args) "
if (args == []) {
System.out.println "\t\tconcHashSet methodMissing: invoke method '$name' with no args "
result = it."$name"()//it.invokeMethod (name)
} else {
System.out.println "\t\tconcHashSet methodMissing: invoke method '$name' with args $args"
result = it.invokeMethod(name, *args)//"$name" (*args)//it.invokeMethod(name, args)
}
System.out.println "\tconcHashSet methodMissing: 'it' is now showing as > '$it'"
"success"
}
//System.out.println "agent protected value is now : " + $concurrentHashSet.val + " and result now $result"
System.out.println "agent protected value is now : " + $concurrentHashSet.val.dump() + " and result now $result"
$concurrentHashSet.val
}
}
但是,当我尝试使用它时 - 它第一次工作,我的字符串被添加,但在第二次调用相同的缺失方法时,agent.send 调用永远不会进行,并且会被跳过。
所以我的简单脚本使用者看起来像这样
// delegates add method via agent.send first time through but not after !
ConcurrentLinkedHashSet conhs = new ConcurrentLinkedHashSet ()
conhs.add ('col1')
println "1st conHashSet as list : ${conhs.toArray()}"
conhs.add ('col2')
println "2nd conHashSet as list : ${conhs.toArray()}"
// direct calls on an agent using invokeMethod
Agent myHash = new Agent (new LinkedHashSet())
myHash {it.invokeMethod ('add', 'col1')}
println "1st agentHashSet as list : ${myHash.val.toArray()}"
myHash {it.invokeMethod ('add','col2')}
println "2nd agentHashSet as list : ${myHash.val.toArray()}"
我的简单跟踪日志在控制台输出上看起来像这样
methodMissing with add and [col1] on org2.softwood.rules.utils.ConcurrentLinkedHashSet@3b0090a4
agent value is : <java.util.LinkedHashSet@0 map=[:]> is instance of: class groovyx.gpars.agent.Agent
concHashSet methodMissing: it is of type class java.util.LinkedHashSet so called [] (add, [col1])
concHashSet methodMissing: invoke method 'add' with args [col1]
concHashSet methodMissing: 'it' is now showing as > '[col1]'
agent protected value is now : <java.util.LinkedHashSet@2eaeb1 map=[col1:java.lang.Object@6a2f6f80]> and result now true
methodMissing with toArray and [] on org2.softwood.rules.utils.ConcurrentLinkedHashSet@3b0090a4
agent value is : <java.util.LinkedHashSet@2eaeb1 map=[col1:java.lang.Object@6a2f6f80]> is instance of: class groovyx.gpars.agent.Agent
agent protected value is now : <java.util.LinkedHashSet@2eaeb1 map=[col1:java.lang.Object@6a2f6f80]> and result now null
1st conHashSet as list : [col1]
methodMissing with add and [col2] on org2.softwood.rules.utils.ConcurrentLinkedHashSet@3b0090a4
agent value is : <java.util.LinkedHashSet@2eaeb1 map=[col1:java.lang.Object@6a2f6f80]> is instance of: class groovyx.gpars.agent.Agent
agent protected value is now : <java.util.LinkedHashSet@2eaeb1 map=[col1:java.lang.Object@6a2f6f80]> and result now null
methodMissing with toArray and [] on org2.softwood.rules.utils.ConcurrentLinkedHashSet@3b0090a4
agent value is : <java.util.LinkedHashSet@2eaeb1 map=[col1:java.lang.Object@6a2f6f80]> is instance of: class groovyx.gpars.agent.Agent
agent protected value is now : <java.util.LinkedHashSet@2eaeb1 map=[col1:java.lang.Object@6a2f6f80]> and result now null
2nd conHashSet as list : [col1]
1st agentHashSet as list : [col1]
2nd agentHashSet as list : [col1, col2]
正如您在第一次尝试委派时看到的那样,您可以看到“concHashSet methodMissing:”跟踪,并且代理在代理中对其调用 invokeMethod 以影响添加元素。
在第二次调用 conhs.add ('col2') 时,agent.sand 调用永远不会发生,因此我的额外项目永远不会被添加。
这很烦人,因为我认为我有一个简单的方法来创建我的 ConcurrentLinkedHashSet,但是代码不起作用。我可以使用什么机制来获得正确的结果?
正如你所看到的,当我直接调用方法(添加)时Agent<LinkedHashSet>
它工作得很好。在我真正的消费类中,如果我用普通的 LinkedHashSet 替换我的 ConcurrentLinkedHashSet 它可以实现梦想,但不是线程安全的。我想创建一个线程安全版本,这取决于试图让它工作。
我想我可以尝试替换代理并仅在我的 LinkedHashSet 周围使用同步块 - 但它有点难看 - 我认为 Gpars 代理会为我将所有这些作为通用解决方案模式作为具有委托的包装器进行排序。
PS我尝试了另一种方法,我认为这种工作方式,但感觉不对 - 它在实现 GroovyInterceptable 的类上使用 @Synchronise on invokeMethod 以在委派时实现线程安全调用。我不确定这是否真的线程安全。
class ConcurrentLinkedHashSet2 implements GroovyInterceptable{
@Delegate private LinkedHashSet $mySet = new LinkedHashSet()
@Synchronized
def invokeMethod (String name, args) {
System.out.println "call to $name intercepted invoke using metaclass invoke"
ConcurrentLinkedHashSet2.metaClass.getMetaMethod(name).invoke (this, *args)
}
}