package multithread; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; /** * The above specifications allow us to determine several properties having to * do with the interaction of waits, notification, and interruption. * * If a thread is both notified and interrupted while waiting, it may either: * * return normally from wait, while still having a pending interrupt (in other * words, a call to Thread.interrupted would return true) * * return from wait by throwing an InterruptedException * * The thread may not reset its interrupt status and return normally from the * call to wait. * * Similarly, notifications cannot be lost due to interrupts. Assume that a set * s of threads is in the wait set of an object m, and another thread performs a * notify on m. Then either: * * at least one thread in s must return normally from wait, or * * all of the threads in s must exit wait by throwing InterruptedException * * Note that if a thread is both interrupted and woken via notify, and that * thread returns from wait by throwing an InterruptedException, then some other * thread in the wait set must be notified. * * @author wa505 * */ public class Monitor { private AtomicBoolean mLock = new AtomicBoolean(); private volatile Thread mHeldThread; private volatile int mHeldCount; /** * Every object, in addition to having an associated monitor, has an associated * wait set. A wait set is a set of threads. When an object is first created, * its wait set is empty. Elementary actions that add threads to and remove * threads from wait sets are atomic. Wait sets are manipulated solely through * the methods Object.wait, Object.notify, and Object.notifyAll. Wait set * manipulations can also be affected by the interruption status of a thread, * and by the Thread class's methods dealing with interruption. Additionally, * the Thread class's methods for sleeping and joining other threads have * properties derived from those of wait and notification actions. */ private List<Waitor> mWaitSet = new ArrayList<>(); private static class Waitor { Thread thread; int waitCount; } private boolean isInWaitingSet() { Thread thread = Thread.currentThread(); synchronized (mWaitSet) { for (Waitor waitor : mWaitSet) { if (waitor.thread == thread) { return true; } } } return false; } /** * Notification actions occur upon invocation of methods notify and notifyAll. * * Let thread t be the thread executing either of these methods on object m, and * let n be the number of lock actions by t on m that have not been matched by * unlock actions. One of the following actions occurs: * * If n is zero, then an IllegalMonitorStateException is thrown. * * This is the case where thread t does not already possess the lock for target * m. * * If n is greater than zero and this is a notify action, then if m's wait set * is not empty, a thread u that is a member of m's current wait set is selected * and removed from the wait set. * * There is no guarantee about which thread in the wait set is selected. This * removal from the wait set enables u's resumption in a wait action. Notice, * however, that u's lock actions upon resumption cannot succeed until some time * after t fully unlocks the monitor for m. * * If n is greater than zero and this is a notifyAll action, then all threads * are removed from m's wait set, and thus resume. * * Notice, however, that only one of them at a time will lock the monitor * required during the resumption of wait. * * */ public void snotifyAll() { if (Thread.currentThread() == mHeldThread) { if (mHeldCount > 0) { synchronized (mWaitSet) { mWaitSet.clear(); } } } } public void snotify() { if (Thread.currentThread() == mHeldThread) { if (mHeldCount > 0) { synchronized (mWaitSet) { mWaitSet.remove(0); } } } } /** * Wait actions occur upon invocation of wait(), or the timed forms wait(long * millisecs) and wait(long millisecs, int nanosecs). * * A call of wait(long millisecs) with a parameter of zero, or a call of * wait(long millisecs, int nanosecs) with two zero parameters, is equivalent to * an invocation of wait(). * * A thread returns normally from a wait if it returns without throwing an * InterruptedException. * * Let thread t be the thread executing the wait method on object m, and let n * be the number of lock actions by t on m that have not been matched by unlock * actions. One of the following actions occurs: * * If n is zero (i.e., thread t does not already possess the lock for target m), * then an IllegalMonitorStateException is thrown. * * If this is a timed wait and the nanosecs argument is not in the range of * 0-999999 or the millisecs argument is negative, then an * IllegalArgumentException is thrown. * * If thread t is interrupted, then an InterruptedException is thrown and t's * interruption status is set to false. * * Otherwise, the following sequence occurs: * * Thread t is added to the wait set of object m, and performs n unlock actions * on m. * * Thread t does not execute any further instructions until it has been removed * from m's wait set. The thread may be removed from the wait set due to any one * of the following actions, and will resume sometime afterward: * * A notify action being performed on m in which t is selected for removal from * the wait set. * * A notifyAll action being performed on m. * * An interrupt action being performed on t. * * If this is a timed wait, an internal action removing t from m's wait set that * occurs after at least millisecs milliseconds plus nanosecs nanoseconds elapse * since the beginning of this wait action. * * An internal action by the implementation. Implementations are permitted, * although not encouraged, to perform "spurious wake-ups", that is, to remove * threads from wait sets and thus enable resumption without explicit * instructions to do so. * * Notice that this provision necessitates the Java coding practice of using * wait only within loops that terminate only when some logical condition that * the thread is waiting for holds. * * Each thread must determine an order over the events that could cause it to be * removed from a wait set. That order does not have to be consistent with other * orderings, but the thread must behave as though those events occurred in that * order. * * For example, if a thread t is in the wait set for m, and then both an * interrupt of t and a notification of m occur, there must be an order over * these events. If the interrupt is deemed to have occurred first, then t will * eventually return from wait by throwing InterruptedException, and some other * thread in the wait set for m (if any exist at the time of the notification) * must receive the notification. If the notification is deemed to have occurred * first, then t will eventually return normally from wait with an interrupt * still pending. * * Thread t performs n lock actions on m. * * If thread t was removed from m's wait set in step 2 due to an interrupt, then * t's interruption status is set to false and the wait method throws * InterruptedException. * * * * * * Interruption actions occur upon invocation of Thread.interrupt, as well as * methods defined to invoke it in turn, such as ThreadGroup.interrupt. * * Let t be the thread invoking u.interrupt, for some thread u, where t and u * may be the same. This action causes u's interruption status to be set to * true. * * Additionally, if there exists some object m whose wait set contains u, then u * is removed from m's wait set. This enables u to resume in a wait action, in * which case this wait will, after re-locking m's monitor, throw * InterruptedException. * * Invocations of Thread.isInterrupted can determine a thread's interruption * status. The static method Thread.interrupted may be invoked by a thread to * observe and clear its own interruption status. */ public void swait() { if (Thread.currentThread() == mHeldThread) { if (mHeldCount > 0) { Waitor w = new Waitor(); w.thread = mHeldThread; w.waitCount = mHeldCount; synchronized (mWaitSet) { mWaitSet.add(w); } for (int i = 0; i < mHeldCount; ++i) { unLock(); } while (isInWaitingSet()) { try { Thread.sleep(0); } catch (InterruptedException e) { mWaitSet.remove(w); } } for (int i = 0; i < w.waitCount; ++i) { lock(); } } } } /** * <p> * The Java programming language provides multiple mechanisms for communicating * between threads. The most basic of these methods is synchronization, which is * implemented using monitors. Each object in Java is associated with a monitor, * which a thread can lock or unlock. Only one thread at a time may hold a lock * on a monitor. Any other threads attempting to lock that monitor are blocked * until they can obtain a lock on that monitor. A thread t may lock a * particular monitor multiple times; each unlock reverses the effect of one * lock operation. * </p> * <p> * The synchronized statement (§14.19) computes a reference to an object; it * then attempts to perform a lock action on that object's monitor and does not * proceed further until the lock action has successfully completed. After the * lock action has been performed, the body of the synchronized statement is * executed. If execution of the body is ever completed, either normally or * abruptly, an unlock action is automatically performed on that same monitor. * </p> * <p> * A synchronized method (§8.4.3.6) automatically performs a lock action when it * is invoked; its body is not executed until the lock action has successfully * completed. * <li>If the method is an instance method, it locks the monitor associated with * the instance for which it was invoked (that is, the object that will be known * as this during execution of the body of the method). * <li>If the method is static, it locks the monitor associated with the Class * object that represents the class in which the method is defined. * <li>If execution of the method's body is ever completed, either normally or * abruptly, an unlock action is automatically performed on that same monitor. * </p> * <p> * The Java programming language neither prevents nor requires detection of * deadlock conditions. Programs where threads hold (directly or indirectly) * locks on multiple objects should use conventional techniques for deadlock * avoidance, creating higher-level locking primitives that do not deadlock, if * necessary. * </p> * <p> * Other mechanisms, such as reads and writes of volatile variables and the use * of classes in the java.util.concurrent package, provide alternative ways of * synchronization. * </p> */ public void lock() { if (Thread.currentThread() != mHeldThread) { while (!mLock.compareAndSet(false, true)) { try { Thread.sleep(0); } catch (InterruptedException e) { } } mHeldThread = Thread.currentThread(); mHeldCount++; } else { mHeldCount++; } } public void unLock() { if (Thread.currentThread() == mHeldThread) { if (mHeldCount > 0) { mHeldCount--; if (mHeldCount == 0) { mHeldThread = null; mLock.getAndSet(false); } } } } }
Java 多线程编程之 notify notifyAll wait lock unlock 算法
写了一个类来理解java 同步机制的算法。这个类并不适合实战,而仅仅是算法层面进行理解。
猜你喜欢
转载自daojin.iteye.com/blog/2391952
今日推荐
周排行