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。
自己的语言表达不是很好,有问题希望大家随时指教。