`

有关semaphore 的死锁的例子。

阅读更多
下面是关于semaphore 的死锁的例子。主要自己学习thinking in java 上面的semaphore的例子的时候不仔细。结果将checkout()  和 checkin()  方法都加上了synchronized. 导致了死锁的问题。代码如下:
public class SemaphoreDemo {
	final static int SIZE = 10;
	public static void main(String[] args) throws Exception {
		final Pool<Fat> pool = new Pool<>(Fat.class, SIZE);
		ExecutorService exec = Executors.newCachedThreadPool();
		for(int i=0; i<SIZE; i++){
			exec.execute(new CheckoutTask<Fat>(pool));
		}
		System.out.println("All checkout task created.");
		TimeUnit.SECONDS.sleep(2);
		List<Fat> list = new ArrayList<>();
		for(int i=0; i<SIZE; i++){
			Fat f = pool.checkout();
			System.out.println(i +": main() thread checkd out");
			f.operation();
			list.add(f);
		}
		Future<?> blocked = exec.submit(new Runnable() {
			@Override
			public void run() {
				try {
					pool.checkout();//这里阻塞住了。
				} catch (InterruptedException e) {
					//acceptable way to exit.
				}
			}
		});
		TimeUnit.SECONDS.sleep(2);
		blocked.cancel(true);//break out of blocked call.
		System.out.println("checking in objects in "+list);
		for(Fat f : list){
			pool.checkin(f);
		}
		for(Fat f : list){//second check in ignored.
			pool.checkin(f);
		}
		exec.shutdownNow();
	}
}
//代理
class Pool<T> {
	private int size;
	//资源类型是一样的。
	private List<T> holder = new ArrayList<>();
	private volatile boolean[] checkedOut;//跟踪checkedout的对象。
	private Semaphore avaliable;
	public Pool(Class<T> resourceType, int size){
		this.size = size;//这个size没有赋值,导致没有调试出来。
		checkedOut = new boolean[size];
		avaliable = new Semaphore(size);//permits.
		//instance resources.
		try{
			for(int i=0; i<size; i++){
				holder.add(resourceType.newInstance());
//				System.out.println(holder.get(i));
			}
		}catch(Exception e){
			throw new RuntimeException(e);
		}
	}
	//对外提供接口
	public synchronized T checkout() throws InterruptedException{
		System.out.println(Thread.currentThread().getName());
		avaliable.acquire();//main  在这里占用着synchronized. 但是在调用avaliable.acquire()的时候阻塞了。
		return getItem();
	}
	public synchronized void checkin(T item){
		boolean released = releaseItem(item);
		if(released){
			avaliable.release();
		}
	}
	private synchronized T getItem(){
		for(int i=0; i<size; i++){
			if(!checkedOut[i]){
				checkedOut[i] = true;
				return holder.get(i);
			}
		}
		return null;//semaphore prevents reaching here.
	}
	private synchronized boolean releaseItem(T item){
		int index = holder.indexOf(item);
		if(index == -1){
			return false;
		}
		if(checkedOut[index]){
			checkedOut[index] = false;
			return true;
		}
		return false;
	}
}
class Fat{
	private static int counter = 0;
	private final int id = counter++;
	public Fat(){}
	public void operation(){
		System.out.println(this+"do operation.");
	}
	@Override
	public String toString() {
		return "id: "+id;
	}
}
class CheckoutTask<T> implements Runnable{
	private Pool<T> pool;
	private static int counter = 0;
	private final int id = counter++;
	public CheckoutTask(Pool<T> pool) {
		this.pool = pool;
	}
	@Override
	public void run() {
		try{
			T resource = pool.checkout();
			System.out.println(this+" checkedout "+ resource);
			TimeUnit.SECONDS.sleep(1);
			System.out.println(this+" checkedin "+resource);
			pool.checkin(resource);
		}catch(InterruptedException e){
		}
	}
	@Override
	public String toString() {
		return "CheckoutTask "+id+" ";
	}
}


死锁出现的原因是:
CheckoutTask 在执行run() 的时候,在方法的内部执行完checkout() 后 ,size 个线程都释放了checkout() 方法上的synchronized修饰的对象的锁,而此时。main ()方法中的 Fat f = pool.checkout(); 执行。由于size 个CheckoutTask 线程还在占用着Semaphore。  所以main 线程在此阻塞。但是main 线程确拿着checkout() 方法上的synchronized 修饰的对象锁。这样就形成了循环等待。即size线程占用着Semaphore ,等待main释放checkout()方法的对象锁。而main 线程占用着checkout() 方法上的对象锁,而等待着使用Semaphore。

自己的语言表达不是很好,有问题希望大家随时指教。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics