【图解Java多线程设计模式】Guarded Suspension模式

如果执行现在的处理会造成问题,就让执行处理的线程进行等待。

示例

一个线程(ClientThread)会将请求(Request)的实例传递给另一个线程(ServerThread),这是一种最简单的线程间通信。

时序图

ijy1bT.md.png

Request.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Request {
private final String name;

public Request(String name) {
this.name = name;
}

public String getName() {
return name;
}

public String toString() {
return "[ Request " + name + " ]";
}
}

RequestQueue.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.LinkedList;
import java.util.Queue;

public class RequestQueue {
private final Queue<Request> queue = new LinkedList<>();

public synchronized void putRequest(Request request) {
queue.offer(request);
notifyAll();
}

public synchronized Request getRequest() {
while (queue.peek() == null) {
try {
wait();
} catch (InterruptedException e) {
}
}

return queue.remove();
}
}

ClientThread.java

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
import java.util.Random;

public class ClientThread extends Thread {
private final RequestQueue requestQueue;
private final Random random;

public ClientThread(RequestQueue requestQueue, String name, long seed) {
super(name);
this.requestQueue = requestQueue;
this.random = new Random(seed);
}

public void run() {
for (int i = 0; i < 10000; i++) {
Request request = new Request("No." + i);
System.out.println(Thread.currentThread().getName() + " requests " + request);
requestQueue.putRequest(request);

try {
Thread.sleep(random.nextInt(1000));
} catch (InterruptedException e) {
}
}
}
}

ServerThread.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.Random;

public class ServerThread extends Thread {
private final RequestQueue requestQueue;
private final Random random;

public ServerThread(RequestQueue requestQueue, String name, long seed) {
super(name);
this.requestQueue = requestQueue;
this.random = new Random(seed);
}

public void run() {
for (int i = 0; i < 10000; i++) {
Request request = requestQueue.getRequest();
System.out.println(Thread.currentThread().getName() + " handles " + request);

try {
Thread.sleep(random.nextInt(1000));
} catch (InterruptedException e) {
}
}
}
}

Main.java

1
2
3
4
5
6
7
8
public class Main {

public static void main(String[] args) {
RequestQueue requestQueue = new RequestQueue();
new ClientThread(requestQueue, "Alice", 3141592L).start();
new ServerThread(requestQueue, "Bobby", 6535897L).start();
}
}

运行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Alice requests [ Request No.0 ]
Bobby handles [ Request No.0 ]
Alice requests [ Request No.1 ]
Alice requests [ Request No.2 ]
Bobby handles [ Request No.1 ]
Bobby handles [ Request No.2 ]
Alice requests [ Request No.3 ]
Bobby handles [ Request No.3 ]
Alice requests [ Request No.4 ]
Bobby handles [ Request No.4 ]
Alice requests [ Request No.5 ]
Alice requests [ Request No.6 ]
Bobby handles [ Request No.5 ]
Bobby handles [ Request No.6 ]

登场角色

GuardedObject(被守护的对象)

GuardedObject角色是一个持有被守护的方法(guardedMethod)的类。当线程执行guardedMethod方法时,若守护条件成立,则可以立即执行;当守护条件不成立时,就要进行等待。守护条件的成立与否会随着GuardedObject角色的状态不同而发生变化。
除了guardedMethod之外,GuardedObject角色还有可能持有其他改变实例状态(特别是改变守护条件)的方法(stateChangingMethod)。
在Java中,guardedMethod通过while语句和wait方法来实现,stateChangingMethod则通过notify/notifyAll方法来实现。
在示例程序中,由RequestQueue类扮演此角色。getRequest方法对应guardedMethod,putRequest方法则对应stateChangingMethod。

类图

ivXEWj.md.png

Timethreads图

ivXeln.md.png

使用java.util.concurrent.LinkedBlockingQueue

RequestQueue.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class RequestQueue {
private final BlockingQueue<Request> queue = new LinkedBlockingQueue<>();

public void putRequest(Request request) {
try {
queue.put(request);
} catch (InterruptedException e) {
}
}

public Request getRequest() {
Request request = null;

try {
request = queue.take();
} catch (InterruptedException e) {
}

return request;
}
}

类图

izCUNq.md.png