/**
 * LOGICAL-PARADOX.ORG
 * Copyright (C)2004 satoshi akabane(akabane@logical-paradox.org)
 *
 */
package org.logical_paradox.common.thread;

import java.util.*;

/**
 * リードライトロックオブジェクト
 * 
 * @author satoshi akabane@logical-paradox.org
 * @version 1.0
 */
public class ReadWriteLock {
	private Set _readerThreads = Collections.synchronizedSet(new HashSet());
	private Set _writerThreads = Collections.synchronizedSet(new HashSet());

	public ReadWriteLock() {
	}
	/**
	 * 読み込みロックを取得する<br>
	 * 指定された時間だけ待ち，それを超えた場合はInterruptedException
	 * 
	 * @param msec 待ち時間(0:完全ブロック)
	 * @throws InterruptedException 何かの原因で失敗した場合
	 */
	public synchronized void beginRead(int msec) throws InterruptedException {
		while(_writerThreads.size() > 0) {
			wait(msec);
		}
		_readerThreads.add(Thread.currentThread());
	}
	/**
	 * 書き込みロックを取得する<br>
	 * 指定された時間だけ待ち，それを超えた場合はInterruptedException
	 * 
	 * @param msec 待ち時間(0:完全ブロック)
	 * @throws InterruptedException 何かの原因で失敗した場合
	 */
	public synchronized void beginWrite(int msec) throws InterruptedException {
		// 書いているスレッドが他に存在するか，誰かが読んでいる場合は停止
		while(_writerThreads.size() > 0 || _readerThreads.size() > 0) {
			wait(msec);
		}
		_writerThreads.add(Thread.currentThread());
	}
	/**
	 * 読み込みロックを解除する
	 * 
	 * @throws InterruptedException 何かの原因で失敗した場合
	 */
	public synchronized void endRead() throws InterruptedException {
		// 現在のスレッドがロック取得者の一覧に存在した場合だけ，ロックの解放処理を実施する
		if(_readerThreads.contains(Thread.currentThread())) {
			_readerThreads.remove(Thread.currentThread());
			notifyAll();
		}
	}
	/**
	 * 書き込みロックを解除する
	 * 
	 * @throws InterruptedException 何かの原因で失敗した場合
	 */
	public synchronized void endWrite() throws InterruptedException {
		// 現在のスレッドがロック取得者の一覧に存在した場合だけ，ロックの解放処理を実施する
		if(_writerThreads.contains(Thread.currentThread())) {
			_writerThreads.remove(Thread.currentThread());
		}
		notifyAll();
	}
	/**
	 * 読み込みロックを取得する<br>
	 * ロックが取得できるまでずっと待つ
	 * 
	 * @throws InterruptedException 何かの原因で失敗した場合
	 */
	public synchronized void beginRead() throws InterruptedException {
		beginRead(0);
	}
	/**
	 * 書き込みロックを取得する<br>
	 * ロックが取得できるまでずっと待つ
	 * 
	 * @throws InterruptedException 何かの原因で失敗した場合
	 */
	public synchronized void beginWrite() throws InterruptedException {
		beginWrite(0);
	}
	/**
	 * 現在のスレッドが所有しているロックを全て解放する
	 * 
	 * @throws InterruptedException
	 */
	public synchronized void release() throws InterruptedException {
		endWrite();
		endRead();
	}
}
