/* WaitLock.java Purpose: Description: History: Wed Mar 2 10:55:54 2005, Created by tomyeh Copyright (C) 2005 Potix Corporation. All Rights Reserved. {{IS_RIGHT This program is distributed under LGPL Version 2.1 in the hope that it will be useful, but WITHOUT ANY WARRANTY. }}IS_RIGHT */ package org.zkoss.util; import org.zkoss.lang.SystemException; import org.zkoss.lang.PotentialDeadLockException; /** * A simple lock used to implement load-on-demand mechanism. * Typical use: a thread, say A, checks whether a resource is loaded, and * put a WaitLock instance if not loaded yet. Then, another thread, say B, * if find WaitLock, it simply calls {@link #waitUntilUnlock} to wait. * Meanwhile, once A completes the loading, it put back the resource * and calls {@link #unlock}. * * <pre><code>WaitLock lock = null; for (;;) { synchronized (map) { Object o = map.get(key); if (o == null) { map.put(key, lock = new WaitLock()); break; //go to load resource } } if (o instanceof MyResource) return (MyResource)o; if (!((Lock)o).waitUntilUnlock(60000)) log.waring("Takes too long"); } //load resource try { .... synchronized (map) { map.put(key, resource); } return resource; } catch (Throwable ex) { synchronized (map) { map.remove(key); } throw SystemException.Aide.wrap(ex); } finally { lock.unlock(); } </code></pre> * * @author tomyeh */ public class WaitLock { private final Thread _locker = Thread.currentThread(); private boolean _unlocked; /** Once created, it is default to be locked. * In other words, other thread's invocation of {@link #waitUntilUnlock} * won't return until {@link #unlock} is called. */ public WaitLock() { } /** Waits this lock to unlock. * * @return whether it is unlocked successfully * @exception SystemException if this thread is interrupted * @exception PotentialDeadLockException if the thread itself creates * this lock. In other words, it tried to wait for itself to complete. */ synchronized public boolean waitUntilUnlock(int timeout) { if (!_unlocked) { if (Thread.currentThread().equals(_locker)) throw new PotentialDeadLockException("Wait for itself?"); try { this.wait(timeout); } catch (InterruptedException ex) { throw SystemException.Aide.wrap(ex); } } return _unlocked; } /** Unlocks any other threads blocked by {@link #waitUntilUnlock}. */ synchronized public void unlock() { _unlocked = true; this.notifyAll(); //wake up all pending } }