要以 PDF 格式阅读此主题,请点击此处

代理

代理是一种特殊用途的线程安全非阻塞实现,其灵感来自 Clojure 中的代理。

简介

代理通过只允许单个**代理管理线程**对它们进行修改来保护可变值。可变值**不能直接从外部访问**,而是必须**将请求发送到代理**,代理保证以调用者的身份顺序处理请求。代理保证所有请求的顺序执行,从而保证值的 一致性。

代理是异步活动对象,接受代码(函数)作为消息。接收后,函数将针对代理的内部状态运行,函数的返回值被认为是代理的新的内部状态。

示意

代理示例
1
2
3
4
5
6
agent = new Agent(0)      //created a new Agent wrapping an integer with initial value 0
agent.send {increment()}  //asynchronous send operation, sending the increment() function
...
//after some delay to process the message, the internal Agent's state has been updated
...
assert agent.val== 1

为了包装整数,我们当然可以使用 Java 平台的*AtomicXXX*类型。当状态或更新算法变得更复杂时,我们需要更多的支持。

示例

另一个示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import groovyx.gpars.agent.Agent

/**
 * Conference stores the number of registrations and allows parties to register and unregister.
 * It inherits from the Agent class and adds the register() and unregister() private methods,
 * which callers may use it the commands they submit to the Conference.
 */
class Conference extends Agent<Long> {
    def Conference() { super(0) }
    private def register(long num) { data += num }
    private def unregister(long num) { data -= num }
}

final Agent conference = new Conference()        //new Conference created

/**
 * Three external parties will try to register/unregister concurrently
 */

final Thread t1 = Thread.start {
    conference << {register(10L)}               //send a command to register 10 attendees
}

final Thread t2 = Thread.start {
    conference << {register(5L)}                //send a command to register 5 attendees
}

final Thread t3 = Thread.start {
    conference << {unregister(3L)}              //send a command to unregister 3 attendees
}

[t1, t2, t3]*.join()
assert 12L == conference.val

有关最新更新,请参阅用户指南中的代理部分以及相应的演示