Java 多线程编程之 notify notifyAll wait lock unlock 算法

写了一个类来理解java 同步机制的算法。这个类并不适合实战,而仅仅是算法层面进行理解。


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);
}
}
}
}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值