「Java 언어로 배우는 디자인 패턴 (멀티 스레드 편)」정리 (그 5)



Guarded Suspension 패턴



Guarded Suspension 패턴에는 guarded wait, spin lock등의 호칭이 있다.

Request.java
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
import java.util.Queue;
import java.util.LinkedList;

public class RequestQueue {
    private final Queue<Request> queue = new LinkedList<Request>();
    public synchronized Request getRequest() {
        while (queue.peek() == null) {
            try {
                wait(); // キューが空の時は待つ(ウェイトセットに入る)
            } catch (InterruptedException e) {
            }
        }
        return queue.remove();
    }
    public synchronized void putRequest(Request request) {
        queue.offer(request);
        notifyAll(); // 待っているスレッドに、キューにrequestが入ったことを知らせる
    }
}

ClientThread.java
import java.lang.Math;

public class ClientThread extends Thread {
    private final RequestQueue requestQueue;
    public ClientThread(RequestQueue requestQueue, String name) {
        super(name);
        this.requestQueue = requestQueue;
    }
    public void run() {
        for (int i = 0; i <= 100; i++) {
            Request request = new Request("No." + i);
            System.out.println(Thread.currentThread().getName() + " put " + request);
            requestQueue.putRequest(request);
            try {
                Thread.sleep((int)(Math.random()*10));
            } catch (InterruptedException e) {
            }
        }
    }
}

ServerThread.java
import java.lang.Math; 

public class ServerThread extends Thread { 
    private final RequestQueue requestQueue; 
    public ServerThread(RequestQueue requestQueue, String name) { 
        super(name); 
        this.requestQueue = requestQueue; 
    } 
    public void run() { 
        for (int i = 0; i <= 100; i++) { 
            Request request = requestQueue.getRequest(); 
            System.out.println(Thread.currentThread().getName() + " get " + request); 
            try { 
                Thread.sleep((int)(Math.random()*10)); 
            } catch (InterruptedException e) { 
            } 
        } 
    } 
}

Main.java
public class Main { 
    public static void main(String[] args) { 
        RequestQueue requestQueue = new RequestQueue(); 
        new ClientThread(requestQueue, "A").start(); 
        new ServerThread(requestQueue, "B").start(); 
    } 
}

실행 결과
...
A put [ Request No.95 ]
B get [ Request No.91 ]
B get [ Request No.92 ]
A put [ Request No.96 ]
A put [ Request No.97 ]
B get [ Request No.93 ]
A put [ Request No.98 ]
B get [ Request No.94 ]
A put [ Request No.99 ]
B get [ Request No.95 ]
B get [ Request No.96 ]
B get [ Request No.97 ]
B get [ Request No.98 ]
B get [ Request No.99 ]
...

ClientThread는 SeverThread에 Request 인스턴스를 전달합니다. 이것은 매우 간단한 스레드 간 통신. ClientThread나 ServerThread를 액티브 오브젝트, RequestQueue를 수동 오브젝트라고 부른다.

ClientThread가 Queue에 요청을 던지고(put), ServerThread가 Queue에서 요청을 꺼낸다(get). put과 get은 synchronized로 배타된다.

getReques 메소드는 가장 오래된 요청을 하나 꺼낸다. 요청이 하나도 없는 경우는, 다른 thread가 putRequest할 때까지 기다린다. queue.peek() != null 이라는 조건 즉 Queue 가 비어 있지 않다는 조건이 채워져 있을 필요가 있다. 이러한 충족되어야하는 조건을 Guarded Suspension 패턴의 가드 조건이라고합니다.

putRequest 메소드는 하나의 요청을 추가한다. 그런 다음 notifyAll에서 기다리는 스레드에 알립니다.

wait와 notify에 대해서는
「Java 언어로 배우는 디자인 패턴 (멀티 스레드 편)」정리 (그 1)
참조.

실행 결과와 같이 B(get)가 A(put)를 추월하지 않는다.

등장인물



GuardedObject 역할은 가드된 메소드(guardedMethod)를 가지고 있는 클래스. 가드 조건이 충족되면 즉시 실행되고, 충족되지 않으면 기다립니다. GuardedObjec 역할은 인스턴스의 상태를 변경하는 메서드(stateChangingMethod)를 가질 수 있다. 샘플 프로그램에서는 RequestQueue 클래스가 이 역할을 맡고, getRequest가 guardedMethod, putRequest가 stateChangingMethod에 대응한다.

관련
「Java 언어로 배우는 디자인 패턴 (멀티 스레드 편)」정리 (그 1)
「Java 언어로 배우는 디자인 패턴 (멀티 스레드 편)」정리 (그 2)
「Java 언어로 배우는 디자인 패턴 (멀티 스레드 편)」정리 (그 3)
「Java 언어로 배우는 디자인 패턴 (멀티 스레드 편)」정리 (그 4)

좋은 웹페이지 즐겨찾기