java 스레드 wait, notify, notify All

3987 단어
wait (), notify (), notify All () 는 Object 클래스의 세 가지 로컬 방법이며,final이며, 다시 쓸 수 없습니다. 즉, 모든 대상이 이 세 가지 방법을 포함하고 있습니다.대체적으로wait() 방법은 이 방법을 호출한 라인으로 하여금 이 대상의 자물쇠를 방출하고 현재의 라인을 막게 하는 것이다.notify () 방법은wait () 방법을 호출해서 막힌 라인을 무작위로 선택하여 막힘을 해소합니다.notifyAll () 방법은 wait () 방법을 호출해서 막힌 모든 라인을 깨우지만, 단 한 라인만 라인 자물쇠를 얻을 수 있습니다.
주의: 이 안에 관련된 라인 조작은 모두 같은 대상입니다. 그렇지 않으면 의미가 없습니다.
    (1)wait()
1. 이 방법을 호출할 때 현재 라인은 대상의 자물쇠를 가지고 있어야 한다.
2. 현재 스레드는 자물쇠를 풀고 막는다.
3. 현재 스레드가 계속 막힐 것입니다. 이 스레드가 다시 대상 자물쇠를 얻고 실행을 회복하지 않는 한.현재 라인을 복구하려면 다른 라인이 notify () 또는 notify All () 방법을 사용해서 이 대상이 잠긴 라인이 복구될 때까지 기다려야 합니다. (현재 라인이 복구될 필요는 없습니다.)
4. 이 방법은 항상 순환에서 사용된다.
synchronized (obj) {
         while (<condition does not hold>)
             obj.wait();
         ... // Perform action appropriate to condition
     }

5. 이 방법은 대상 자물쇠가 있는 라인에 호출되어야 한다. 그렇지 않으면 이상이 던진다.
(2) notify () 1. 현재 대상 자물쇠를 기다리고 있는 라인을 깨웁니다.만약 여러 개의 라인이 현재 대상 자물쇠를 기다리고 있다면, 단지 한 라인만 깨어날 것이다.
2. 깨어난 라인은 현재 라인이 대상의 자물쇠를 풀 때까지 즉시 실행하지 않습니다.
3. 이 방법은 대상 자물쇠가 있는 라인에 호출되어야 한다. 그렇지 않으면 이상이 던진다.
    (3)notifyAll()
1. 현재 대상이 잠긴 모든 라인을 깨우는 것은 notify ()와 다르다.
2. 깨어난 라인은 현재 라인이 대상의 자물쇠를 풀 때까지 즉시 실행하지 않습니다.또한 깨어난 모든 라인은 공정한 경쟁을 벌여 대상을 확보하고 집행한다.
3. 이 방법은 대상 자물쇠가 있는 라인에 호출되어야 한다. 그렇지 않으면 이상이 던진다.
참고:
1. 이 세 가지 방법을 호출할 때 라인은 반드시 이 대상에 대한 자물쇠를 가져야 한다. 그렇지 않으면 Illegal Monitor State Exception 이상을 던질 것이다.보통synchronized 방법이나 블록에서 라인이 자물쇠를 가지게 됩니다.
2. notify () 와 notify All () 방법을 호출하면 깨어난 라인은 즉시 실행되지 않고 대상 자물쇠를 가진 라인이 자물쇠를 풀릴 때까지 기다려야 실행됩니다.
3. notify()와 notifyAll()의 큰 차이점은 다음과 같다. notify()는 몇 개의 라인이 막혀도 한 라인만 깨우면 다른 막힌 라인은 깨우지 않고 깨어난 라인만 실행되며 다른 막힌 라인은 계속 막힌다.notifyAll () 는 모든 막힌 라인을 깨우고, 이 라인들은 실행됩니다. (대상의 자물쇠를 얻는 전제 조건)
예는 다음과 같습니다.
package test.thread;

import java.util.ArrayList;
import java.util.List;

/**
 *  
 * 
 */
public class Test {
	public static void main(String[] args) {
		final Bean bean = new Bean();
		new Thread(new Runnable() {
			public void run() {
				for (int i = 0; i < 50; i++)
					bean.create();
			}
		}).start();
		for (int i = 0; i < 50; i++)
			bean.use();
	}
}

class Bean {
	private List<String> list = new ArrayList<String>();

	/**
	 *  
	 * 
	 */
	public synchronized void create() {
		while (list.size() != 0) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		for (int i = 0; i < 10; i++) {
			System.out.println("Create Bean:" + i);
			list.add("Bean: " + i);
		}
		this.notify();
	}

	/**
	 *  
	 * 
	 */
	public synchronized void use() {
		while (list.size() != 10) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		while (list.size() > 0) {
			System.out.println(list.remove(0));
		}

		this.notify();
	}
}

자물쇠를 쉽게 만드는 예를 하나 더 들면 다음과 같다.
4
package test.thread;

import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Stack {

	LinkedList list = new LinkedList();

	public synchronized void push(Object x) {
		synchronized (list) {
			list.addLast(x);
			notify();
		}
	}

	public synchronized Object pop() throws Exception {
		synchronized (list) {
			if (list.isEmpty()) {
				wait();
			}

			return list.removeFirst();
		}
	}

	public static void main(String[] args) {
		final Stack s = new Stack();
		ExecutorService exec = Executors.newCachedThreadPool();
		exec.execute(new Runnable() {
			public void run() {
				try {
					System.out.println(s.pop());
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
		exec.execute(new Runnable() {
			public void run() {
				s.push("test");
			}
		});
		exec.shutdown();
	}

}
상례에서wait()와notify() 방법을 호출할 때 Stack 대상의 자물쇠만 풀었지만 링크드 리스트 대상의 자물쇠가 풀리지 않았을 수도 있다. 그러면 프로그램 경쟁인 링크드 리스트 대상의 자물쇠가 풀려 사라질 수 있다.

좋은 웹페이지 즐겨찾기