节点状态
#因超时或中断,该线程被取消
/** waitStatus value to indicate thread has cancelled */
static final int CANCELLED = 1;
#该线程的后继线程已阻塞,当该线程release或cancel要重启这个后继线程
/** waitStatus value to indicate successor's thread needs unparking */
static final int SIGNAL = -1;
#表明该线程被处于条件队列,就是因为调用了Condition.await而被阻塞
/** waitStatus value to indicate thread is waiting on condition */
static final int CONDITION = -2;
/**
* waitStatus value to indicate the next acquireShared should
* unconditionally propagate
*/
模板方法
- tryAcquire(int arg) :独占式获取同步状态,该方法需要查询当前状态并判断同步状态是否符合预期,然后再进行CAS设置同步状态
- tryRelease(int arg) :独占式释放同步状态,等待获取同步状态的线程将有机会获取同步状态
- tryAcquireShared(int arg) :共享式获取同步状态,返回大于等于0的值,表示获取成功,否则失败
- tryReleaseShared(int arg): 共享式释放同步状态
- isHeldExclusively() :当前同步器是否在独占模式下被线程占用,一般该方法表示是否被前当线程多独占
公平
判断前驱节点是否为头节点
https://www.cnblogs.com/yulinfeng/p/6899316.html
抢占式和共享式
注意:和公平性无关
抢占式:
- 可重入锁
共享式:
参考:https://www.cnblogs.com/uodut/p/6830939.html
-
CountDownLatch
-
Semaphore
复杂资源竞争
(一) 图书馆有100个座位,每位进入图书馆的读者要在登记表上登记,退出时要在登记表上注销。要几个程序?有多少个进程?(答:一个程序;为每个读者设一个进程)
(1) 当图书馆中没有座位时,后到的读者在图书馆为等待(阻塞)
(2) 当图书馆中没有座位时,后到的读者不等待,立即回家。
解(1 )
设信号量:S=100; MUTEX=1
P(S)
P(MUTEX)
登记
V(MUTEX)
阅读
P(MUTEX)
注销
V(MUTEX)
V(S)
解(2)
设整型变量 COUNT=100;
信号量:MUTEX=1;
P(MUTEX);
IF (COUNT==0)
{ V(MUTEX);
RETURN;
}
COUNT=COUNT-1;
登记
V(MUTEX);
阅读
P(MUTEX);
COUNT=COUNT+1;
V(MUTEX);
RETURN;
(二) 有一座东西方向的独木桥;用P,V操作实现:
(1) 每次只允许一个人过桥;
(2) 当独木桥上有行人时,同方向的行人可以同时过桥,相反方向的人必须等待。
(3) 当独木桥上有自东向西的行人时,同方向的行人可以同时过桥,从西向东的方向,只允许一个人单独过桥。(此问题和读者与写者问题相同,东向西的为读者,西向东的为写者)。
(1)解
设信号量 MUTEX=1
P (MUTEX)
过桥
V (MUTEX)
(2)解
设信号量: MUTEX=1 (东西方互斥)
MD=1 (东向西使用计数变量互斥)
MX=1 (西向东使用计数变量互斥)
设整型变量: CD=0 (东向西的已上桥人数)
CX=0 (西向东的已上桥人数)
从东向西:
P (MD)
IF (CD=0)
{P (MUTEX) }
CD=CD+1
V (MD)
过桥
P (MD)
CD=CD-1
IF (CD=0)
{V (MUTEX) }
V (MD)
从西向东:
P (MX)
IF (CX=0)
{P (MUTEX) }
CX=CX+1
V (MX)
过桥
P (MX)
CX=CX-1
IF (CX=0)
{V (MUTEX) }
V (MX)
(3) 解:从东向西的,和(2)相同;从西向东的和(1)相同。
(三) 有一个俱乐部,有甲乙两个服务员,当顾客有请求时,甲负责送烟,乙负责送火,无顾客请求时,服务员睡眠。顾客自己不能带烟和火,当顾客要抽烟时,可请求服务员送烟和火,烟和火还未送到时,顾客必须等待。
设信号量:SY, SH,CY,CH:初值都为0
甲服务员
REPEAT
P(SY)
送烟
V(CY)
UNTIL FALSE
乙服务员
REPEAT
P(SH)
送火
V(CH)
UNTIL FALSE
顾客
V(SY) /*(请求送烟)*/
V(SH) /*(请求送火)*/
P(CY) /* (等烟) */
P(CH) /* (等火) */
抽烟
(四)一家四人父、母、儿子、女儿围桌而坐;桌上有一个水果盘;
(1) 当水果盘空时,父亲可以放香蕉或者母亲可以放苹果,但盘中已有水果时,就不能放,父母等待。当盘中有香蕉时,女儿可吃香蕉,否则,女儿等待;当盘中有苹果时,儿子可吃,否则,儿子等待。
解 设信号量:SE=1(空盘子);SA=0 (放了苹果的盘子);SB=0 (放了香蕉的盘子)
父亲
REPEAT
剥香蕉
P(SE)
放香蕉
V(SB)
UNTIL FALSE
母亲
REPEAT
削苹果
P(SE)
放苹果
V(SA)
UNTIL FALSE
儿子
P(SA)
拿苹果
V(SE)
吃苹果
女儿
P(SB)
拿香蕉
V(SE)
吃香蕉
(2) 把(1)改为:儿子要吃苹果时,请母亲放苹果,女儿要吃香蕉时,请父亲放香蕉,(还是盘子为空时才可以放)。
(2)解:再增加两个信号量:SF=0, SM=0
父亲
REPEAT
P(SF)
剥香蕉
P(SE)
放香蕉
V(SB)
UNTIL FALSE
母亲
REPEAT
P(SM)
削苹果
P(SE)
放苹果
V(SA)
UNTIL FALSE
儿子
V(SM)
P(SA)
拿苹果
V(SE)
吃苹果
女儿
V(SF)
P(SB)
拿香蕉
V(SE)
吃香蕉
(五)有一个超市,最多可容纳N个人进入购物,当N个顾客满员时,后到的顾客在超市外等待;超市中只有一个收银员。可以把顾客和收银员看作两类进程,两类进程间存在同步关系。写出用P;V操作实现的两类进程的算法(2003年系统设计员考试的题目)
解:设信号量:S=0,C=0(顾客与收银员的同步信号量),M=N
收银员
P(S)
收银
V(C)
顾客
P(M)
进入店内购物
V(S)
P(C)
V(M)
(六)有一个理发店,店内共有20个座位供顾客等待理发,(进入理发店的顾客,都在此座位上等待理发,正在理发的顾客不占用此座位),当20个座位坐满了,后到的顾客不等待,立即回家。当没有顾客时,理发师睡眠等待。
解:设信号量:S=0.C=0,MUTEX=1
设整型变量 SM=20
理发师
REPEAT
P(S) -------如无顾客,理发师等待
V(C) 叫一个顾客理发
理发
UNTIL FALSE
顾客
P(MUTEX)
IF (SM=0)
{ V(MUTEX)――――满座,离开,回家
RETURN
ELSE
SM=SM-1―――――空座位数减 1
V(MUTEX)
}
V(S)――――――――通知理发师,增加了一个顾客,如理发师在等待则唤醒他
P(C) ———————等理发师叫自己理发
P(MUTEX)
SM=SM+1―――――被叫到,释放一个空的座位
V(MUTEX)
接受理发
如果此题改为:满座时,顾客等待空座位:则 顾客进程的程序修改如下:
把SM设为信号量 SM=20
顾客
P(SM) ---------------------申请一个座位,无则等待
V(S)――――――――通知理发师,增加了一个顾客,如理发师在等待则唤醒他
P(C) ———————等理发师叫自己理发
V(SM)
接受理发
(七)一个盒子,内有黑白两种棋子(数量相等),甲每次从盒子中取出一颗黑子,乙每次从盒子中取出一颗白子,一人取了棋子后,必须等另一方取过棋子方可再取,(可假设甲先取)。
解: 设信号量:SJ=1,SY=0
甲
REPEAT
P(SJ)
取一颗黑子
V(SY)
UNTIL 盒子中无黑子
乙
REPEAT
P(SY)
取一颗白子
V(SJ)
UNTIL 盒子中无白子
(八)按要求完成下面的程序。设有三个进程,input进程、compute进程和output进程;它们通过共享一个缓冲区buf的合作关系如下:
(1)input进程每次输入数据后,把数据送到buf,供compute进程计算和output进程打印;
(2)comput进程每次从buf取出已输入的可计算的数据进行计算,并当output进程把输入数据打印完成后,把计算结果送入buf供output进程打印;
(3)output进程每次按顺序把buf中的输入数据和计算结果在打印机上输出。
解:
设信号量:sa=1,sb=sc=sd=0, 请把能正确实现这三个进程同步关系的P、V操作的语句填入下面的程序。
procedure input
begin
local data
repeat
get(data); /*输入数据到data*/
p(sa);
buf=data;
(1)
V ( sc )
v(sb);
until false
end;
procedure compute
begin
locol data
repeat
(2)
P ( sb )
data=buf;
计算data并把结果保存在data;
(3)
P ( sd )
buf=data;
v(sc);
until false
end;
procedure output
begin
local data
repeat
P(sc)
打印 buf;
(4)
V ( sd )
p(sc)
打印 buf;
v(sa);
until false
end;
与抢占式区别:https://www.jianshu.com/p/76949bca657a
死锁
多个生产者、多个消费者会在时序情况下产生死锁
自编同步队列代码设计
package practise;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.AbstractOwnableSynchronizer;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.LockSupport;
public class AbstractQueuedSynchronizerP extends AbstractOwnableSynchronizer{
private transient AtomicReference<Node> head = new AtomicReference<>();
/**
* Tail of the wait queue, lazily initialized. Modified only via
* method enq to add new wait node.
*/
private transient AtomicReference<Node> tail = new AtomicReference<>();
/**
* The synchronization state.
*/
protected AtomicInteger state =new AtomicInteger();
static final class Node {
/** Marker to indicate a node is waiting in shared mode */
static final Node SHARED = new Node();
/** Marker to indicate a node is waiting in exclusive mode */
static final Node EXCLUSIVE = null;
/** waitStatus value to indicate thread has cancelled */
static final int CANCELLED = 1;
/** waitStatus value to indicate successor's thread needs unparking */
static final int SIGNAL = -1;
/** waitStatus value to indicate thread is waiting on condition */
static final int CONDITION = -2;
/**
* waitStatus value to indicate the next acquireShared should
* unconditionally propagate
*/
static final int PROPAGATE = -3;
AtomicInteger waitStatus=new AtomicInteger();
AtomicReference<Node> prev =new AtomicReference<>();
AtomicReference<Node> next=new AtomicReference<>();
AtomicReference<Thread> thread=new AtomicReference<>();
Node nextWaiter;
/**
* Returns true if node is waiting in shared mode
*/
final boolean isShared() {
return nextWaiter == SHARED;
}
/**
* Returns previous node, or throws NullPointerException if null.
* Use when predecessor cannot be null. The null check could
* be elided, but is present to help the VM.
*
* @return the predecessor of this node
*/
final Node predecessor() throws NullPointerException {
Node p = prev.get();
if (p == null)
throw new NullPointerException();
else
return p;
}
Node() { // Used to establish initial head or SHARED marker
}
Node(Thread thread, Node mode) { // Used by addWaiter
this.nextWaiter = mode;
this.thread.set(thread);
}
Node(Thread thread, int waitStatus) { // Used by Condition
this.waitStatus.set(waitStatus);
this.thread.set(thread);
}
}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head.get() && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
private void setHead(Node node) {
head.set(node);
node.thread = null;
node.prev = null;
}
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
private void cancelAcquire(Node node) {
// Ignore if node doesn't exist
if (node == null)
return;
node.thread = null;
// Skip cancelled predecessors
Node pred = node.prev.get();
while (pred.waitStatus.get() > 0){
pred = pred.prev.get();
node.prev.set(pred);
}
// predNext is the apparent node to unsplice. CASes below will
// fail if not, in which case, we lost race vs another cancel
// or signal, so no further action is necessary.
Node predNext = pred.next.get();
// Can use unconditional write instead of CAS here.
// After this atomic step, other Nodes can skip past us.
// Before, we are free of interference from other threads.
node.waitStatus.set(Node.CANCELLED);
// If we are the tail, remove ourselves.
if (node == tail.get() && tail.compareAndSet(node, pred)) {
pred.next.compareAndSet(predNext, null);
} else {
// If successor needs signal, try to set pred's next-link
// so it will get one. Otherwise wake it up to propagate.
int ws;
if (pred != head.get() &&
((ws = pred.waitStatus.get()) == Node.SIGNAL ||
(ws <= 0 && pred.waitStatus.compareAndSet(ws, Node.SIGNAL))) &&
pred.thread != null) {
Node next = node.next.get();
if (next != null && next.waitStatus.get() <= 0)
pred.next.compareAndSet(predNext, next);
} else {
unparkSuccessor(node);
}
node.next.set(node);; // help GC
}
}
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus.get();
if (ws < 0)
node.waitStatus.compareAndSet(ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
Node s = node.next.get();
if (s == null || s.waitStatus.get() > 0) {
s = null;
for (Node t = tail.get(); t != null && t != node; t = t.prev.get())
if (t.waitStatus.get() <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread.get());
}
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus.get();
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
pred = pred.prev.get();
node.prev.set(pred);
} while (pred.waitStatus.get() > 0);
pred.next.set(node);
} else {
pred.waitStatus.compareAndSet(ws, Node.SIGNAL);
}
return false;
}
private static void selfInterrupt() {
Thread.currentThread().interrupt();
}
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail.get();
if (pred != null) {
//设置前置
node.prev.set(pred);;
if (tail.compareAndSet(pred, node)) {
pred.next.set(node);
return node;
}
}
enq(node);
return node;
}
private Node enq(final Node node) {
for (;;) {
Node t = tail.get();
if (t == null) { // Must initialize
if (head.compareAndSet(null, new Node()))
tail.set(head.get());
} else {
//尾节点是作为增加节点,即要增加的节点要指向上队列尾节点,再得到的尾节点next设置要增加的节点
node.prev.set(t);
if (tail.compareAndSet(t, node)) {
t.next.set(node);
return t;
}
}
}
}
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head.get();
if (h != null && h.waitStatus.get()!= 0)
unparkSuccessor(h);
return true;
}
return false;
}
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
public final boolean hasQueuedPredecessors() {
Node t = tail.get(); // Read fields in reverse initialization order
Node h = head.get();
Node s;
boolean has=h != t;//有后续节点
if (!has) {
return has;
}
s = h.next.get();
boolean f;
if (s==null||s.thread.get()!=Thread.currentThread()) {
System.out.println("节点是空的或者是不是当前线程");
f=true;
}else {
f=false;
}
return has&&f;
}
public String toString() {
String q = tail==head ? "non" : "";
Node t=tail.get();
List<Node> list=new ArrayList<>();
for (Node p = tail.get(); p != null; p = p.prev.get()) {
if (t != null)
list.add(p);
}
return list.toString() ;
}
final boolean transferForSignal(Node node) {
/*
* If cannot change waitStatus, the node has been cancelled.
*/
if (!node.waitStatus.compareAndSet(Node.CONDITION, 0))
return false;
/*
* Splice onto queue and try to set waitStatus of predecessor to
* indicate that thread is (probably) waiting. If cancelled or
* attempt to set waitStatus fails, wake up to resync (in which
* case the waitStatus can be transiently and harmlessly wrong).
*/
Node p = enq(node);
int ws = p.waitStatus.get();
if (ws > 0 || !p.waitStatus.compareAndSet(ws, Node.SIGNAL)){
//根据线程解锁
LockSupport.unpark(node.thread.get());
System.out.println("123asd12");
}
return true;
}
final int fullyRelease(Node node) {
boolean failed = true;
try {
int savedState = state.get();
if (release(savedState)) {
failed = false;
return savedState;
} else {
throw new IllegalMonitorStateException();
}
} finally {
if (failed)
node.waitStatus.set(Node.CANCELLED);
}
}
final boolean isOnSyncQueue(Node node) {
if (node.waitStatus.get() == Node.CONDITION || node.prev == null)
return false;
if (node.next != null) // If has successor, it must be on queue
return true;
/*
* node.prev can be non-null, but not yet on queue because
* the CAS to place it on queue can fail. So we have to
* traverse from tail to make sure it actually made it. It
* will always be near the tail in calls to this method, and
* unless the CAS failed (which is unlikely), it will be
* there, so we hardly ever traverse much.
*/
return findNodeFromTail(node);
}
/**
* Returns true if node is on sync queue by searching backwards from tail.
* Called only when needed by isOnSyncQueue.
* @return true if present
*/
private boolean findNodeFromTail(Node node) {
Node t = tail.get();
for (;;) {
if (t == node)
return true;
if (t == null)
return false;
t = t.prev.get();
}
}
final boolean transferAfterCancelledWait(Node node) {
if (node.waitStatus.compareAndSet(Node.CONDITION, 0)) {
enq(node);
return true;
}
/*
* If we lost out to a signal(), then we can't proceed
* until it finishes its enq(). Cancelling during an
* incomplete transfer is both rare and transient, so just
* spin.
*/
while (!isOnSyncQueue(node))
Thread.yield();
return false;
}
public class ConditionObject {
private static final long serialVersionUID = 1173984872572414699L;
/** First node of condition queue. */
private transient Node firstWaiter;
/** Last node of condition queue. */
private transient Node lastWaiter;
/**
* Creates a new <tt>ConditionObject</tt> instance.
*/
public ConditionObject() { }
// Internal methods
/**
* Adds a new waiter to wait queue.
* @return its new wait node
*/
private Node addConditionWaiter() {
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
if (t != null && t.waitStatus.get()!= Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter;
}
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node;
else
t.nextWaiter = node;
lastWaiter = node;
return node;
}
/**
* Removes and transfers nodes until hit non-cancelled one or
* null. Split out from signal in part to encourage compilers
* to inline the case of no waiters.
* @param first (non-null) the first node on condition queue
*/
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
/**
* Removes and transfers all nodes.
* @param first (non-null) the first node on condition queue
*/
private void doSignalAll(Node first) {
lastWaiter = firstWaiter = null;
do {
Node next = first.nextWaiter;
first.nextWaiter = null;
transferForSignal(first);
first = next;
} while (first != null);
}
private void unlinkCancelledWaiters() {
Node t = firstWaiter;
Node trail = null;
while (t != null) {
Node next = t.nextWaiter;
if (t.waitStatus.get() != Node.CONDITION) {
t.nextWaiter = null;
if (trail == null)
firstWaiter = next;
else
trail.nextWaiter = next;
if (next == null)
lastWaiter = trail;
}
else
trail = t;
t = next;
}
}
// public methods
public final void signal() {
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
public final void signalAll() {
Node first = firstWaiter;
if (first != null)
doSignalAll(first);
}
public final void awaitUninterruptibly() {
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
boolean interrupted = false;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if (Thread.interrupted())
interrupted = true;
}
if (acquireQueued(node, savedState) || interrupted)
selfInterrupt();
}
/*
* For interruptible waits, we need to track whether to throw
* InterruptedException, if interrupted while blocked on
* condition, versus reinterrupt current thread, if
* interrupted while blocked waiting to re-acquire.
*/
/** Mode meaning to reinterrupt on exit from wait */
private static final int REINTERRUPT = 1;
/** Mode meaning to throw InterruptedException on exit from wait */
private static final int THROW_IE = -1;
/**
* Checks for interrupt, returning THROW_IE if interrupted
* before signalled, REINTERRUPT if after signalled, or
* 0 if not interrupted.
*/
private int checkInterruptWhileWaiting(Node node) {
return Thread.interrupted() ?
(transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
0;
}
/**
* Throws InterruptedException, reinterrupts current thread, or
* does nothing, depending on mode.
*/
private void reportInterruptAfterWait(int interruptMode)
throws InterruptedException {
if (interruptMode == THROW_IE)
throw new InterruptedException();
else if (interruptMode == REINTERRUPT)
selfInterrupt();
}
/**
* Implements interruptible condition wait.
* <ol>
* <li> If current thread is interrupted, throw InterruptedException.
* <li> Save lock state returned by {@link #getState}.
* <li> Invoke {@link #release} with
* saved state as argument, throwing
* IllegalMonitorStateException if it fails.
* <li> Block until signalled or interrupted.
* <li> Reacquire by invoking specialized version of
* {@link #acquire} with saved state as argument.
* <li> If interrupted while blocked in step 4, throw InterruptedException.
* </ol>
*/
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
System.out.println(this.getClass().getSimpleName());
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
/**
// support for instrumentation
/**
* Returns true if this condition was created by the given
* synchronization object.
*
* @return {@code true} if owned
*/
final boolean isOwnedBy(AbstractQueuedSynchronizerP sync) {
return sync == AbstractQueuedSynchronizerP.this;
}
/**
* Queries whether any threads are waiting on this condition.
* Implements {@link AbstractQueuedSynchronizer#hasWaiters}.
*
* @return {@code true} if there are any waiting threads
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
* returns {@code false}
*/
protected final boolean hasWaiters() {
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
if (w.waitStatus.get() == Node.CONDITION)
return true;
}
return false;
}
/**
* Returns an estimate of the number of threads waiting on
* this condition.
* Implements {@link AbstractQueuedSynchronizer#getWaitQueueLength}.
*
* @return the estimated number of waiting threads
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
* returns {@code false}
*/
protected final int getWaitQueueLength() {
int n = 0;
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
if (w.waitStatus.get() == Node.CONDITION)
++n;
}
return n;
}
/**
* Returns a collection containing those threads that may be
* waiting on this Condition.
* Implements {@link AbstractQueuedSynchronizer#getWaitingThreads}.
*
* @return the collection of threads
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
* returns {@code false}
*/
protected final Collection<Thread> getWaitingThreads() {
ArrayList<Thread> list = new ArrayList<Thread>();
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
if (w.waitStatus.get() == Node.CONDITION) {
Thread t = w.thread.get();
if (t != null)
list.add(t);
}
}
return list;
}
public void name() {
System.out.println(this.getClass().getName());
}
}
public ConditionObject name() {
return new ConditionObject();
}
static AbstractQueuedSynchronizerP lock=new AbstractQueuedSynchronizerP();
public static void main(String[] args) {
//这个有问题的,获取状态和释放查看ReentrantLock源码
ConditionObject conditionObject=lock.name();
conditionObject.name();
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
lock.acquire(1);
try {
System.out.println("f");
Thread.sleep(1000);
} catch (InterruptedException e) {
}
lock.release(1);
}
}).start();
}
}
}
不加入状态设计
package practise;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;
public class AbstractQueuedSynchronizer {
private Thread thread;
private AtomicInteger state=new AtomicInteger();
private AtomicReference<Node> head=new AtomicReference<>();
private AtomicReference<Node> tail=new AtomicReference<>();
public boolean acquire(int arg) {
if (!tryAcquire(arg)) {
if (tail.get()==null) {
Node node=new Node();
tail.set(node);
head.set(node);
}
//这里构造老有问题
Node t=tail.get();
Node node=new Node(Thread.currentThread(),t,null);
tail.set(node);
t.next.set(node);
return acquireQueue(node);
}
return true;
}
public boolean release(int arg) {
int s=state.get();
int update=s-arg;
System.out.println(update);
if (update==0) {
//真的难以想象,这里进行CAS操作的时候释放会有问题
state.compareAndSet(s,update);
thread=null;
Node node=head.get().next.get();
if (node==null) {
return true;
}
LockSupport.unpark(node.thread);
return true;
}
return false;
}
/**
*
* @param node
* @return
*/
private boolean acquireQueue(Node node) {
while (true) {
Node prev=node.prev.get();
if (prev==head.get()&&tryAcquire(1)) {
head.set(node);
node.prev=null;
node.thread=null;
prev.next=null;
return true;
}
LockSupport.park(this);
}
}
public boolean tryAcquire(int arg) {
int s=state.get();
Thread t=Thread.currentThread();
if (s==0) {
// state.compareAndSet(s,arg);
if (!hasQueuedPredecessors()&& state.compareAndSet(0,arg)) {
thread=Thread.currentThread();
return true;
}
}else if (t==thread) {
state.compareAndSet(s,s+arg);
return true;
}
return false;
}
public final boolean hasQueuedPredecessors() {
//头结点未初始化,false-->可获得锁
// 且头指针下一节点和当前线程对象不一致,返回false
Node t = tail.get(); // Read fields in reverse initialization order
Node h = head.get();
Node s;
return h != t &&
((s = h.next.get()) == null || s.thread != Thread.currentThread());
}
static class Node{
static int i=0;
Thread thread;
AtomicReference<Node> prev=new AtomicReference<>();
AtomicReference<Node> next=new AtomicReference<>();
/**
*
*/
public Node() {
i++;
}
/**
* @param thread
* @param prev
* @param next
*/
public Node(Thread thread, Node prev, Node next) {
super();
i++;
this.thread = thread;
this.prev.set(prev);
this.next.set(next);
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Node [toString()=" +i + "]";
}
}
public static void main(String[] args) {
AbstractQueuedSynchronizer lock=new AbstractQueuedSynchronizer();
for (int i = 0; i < 3; i++) {
Thread thread=new Thread(new Runnable() {
@Override
public void run() {
lock.acquire(1);
try {
System.out.println("f");
Thread.sleep(3000);
} catch (InterruptedException e) {
}
lock.release(1);
}
});
thread.setName("thread"+i);
thread.start();
}
}
}
看了半天设计不出来,还是原样参考队列同步器设计思路改造了,现在已经具备锁功能,把它的状态设计给去掉了
package practise;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;
public class AbstractQueuedSynchronizer {
private Thread thread;
private AtomicInteger state=new AtomicInteger();
private AtomicReference<Node> head=new AtomicReference<>();
private AtomicReference<Node> tail=new AtomicReference<>();
public boolean acquire(int arg) {
if (!tryAcquire(arg)) {
Node node=new Node();
node.thread.set(Thread.currentThread());
Node t=tail.get();
if (tail.get()!=null) {
node.prev.set(t);
//尾指针要CAS操作
if(tail.compareAndSet(t, node)){
t.next.set(node);
}else{
t=tail.get();
while(true){
node.prev.set(t);
if(tail.compareAndSet(t, node)){
t.next.set(node);
break;
}
}
}
}else{
Node initNode=new Node();
tail.set(initNode);
head.set(initNode);
t=tail.get();
while(true){
node.prev.set(t);
if(tail.compareAndSet(t, node)){
t.next.set(node);
break;
}
}
}
return acquireQueue(node);
}
return true;
}
public boolean release(int arg) {
int s=state.get();
if (Thread.currentThread() != thread)
throw new IllegalMonitorStateException();
int c=s-arg;
boolean free = false;
if (c == 0) {
free = true;
thread=null;
}
state.set(c);
System.out.println(c);
if (free) {
Node node=head.get().next.get();
if (node!=null) {
LockSupport.unpark(node.thread.get());
}
return true;
}
return false;
}
/**
*
* @param node
* @return
*/
private boolean acquireQueue(Node node) {
while (true) {
Node prev=node.prev.get();
if (prev==head.get()&&tryAcquire(1)) {
head.set(node);
node.prev=null;
node.thread=null;
prev.next=null;
return true;
}
LockSupport.park(this);
}
}
public boolean tryAcquire(int arg) {
int s=state.get();
Thread t=Thread.currentThread();
if (s==0) {
// state.compareAndSet(s,arg);
if (!hasQueuedPredecessors()&& state.compareAndSet(0,arg)) {
thread=Thread.currentThread();
return true;
}
}else if (t==thread) {
state.compareAndSet(s,s+arg);
return true;
}
return false;
}
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail.get(); // Read fields in reverse initialization order
Node h = head.get();
Node s;
return h != t &&
((s = h.next.get()) == null || s.thread.get() != Thread.currentThread());
}
static class Node{
static int i=0;
AtomicReference<Thread> thread=new AtomicReference<Thread>();
AtomicReference<Node> prev=new AtomicReference<>();
AtomicReference<Node> next=new AtomicReference<>();
/**
*
*/
public Node() {
i++;
}
/**
* @param thread
* @param prev
* @param next
*/
public Node(Thread thread, Node prev, Node next) {
super();
i++;
this.thread.set(thread) ;
this.prev.set(prev);
this.next.set(next);
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Node [toString()=" +i + "]";
}
}
public static void main(String[] args) {
AbstractQueuedSynchronizer lock=new AbstractQueuedSynchronizer();
for (int i = 0; i < 3; i++) {
Thread thread=new Thread(new Runnable() {
@Override
public void run() {
lock.acquire(1);
try {
System.out.println("f");
Thread.sleep(1000);
} catch (InterruptedException e) {
}
lock.release(1);
}
});
thread.setName("thread"+i);
thread.start();
}
}
}
ConcurrentHashMap中Size大小计算
计算被修改变量两次总和是否发生变化,若发生变化上锁计数,最后释放锁
//贴了下源码,面试过程中,平时看的源码都是记不住,问我如何实现,我只是有个印象
public int size() {
// Try a few times to get accurate count. On failure due to
// continuous async changes in table, resort to locking.
final Segment<K,V>[] segments = this.segments;
int size;
boolean overflow; // true if size overflows 32 bits
long sum; // sum of modCounts
long last = 0L; // previous sum
int retries = -1; // first iteration isn't retry
try {
for (;;) {
if (retries++ == RETRIES_BEFORE_LOCK) {
for (int j = 0; j < segments.length; ++j)
ensureSegment(j).lock(); // force creation
}
sum = 0L;
size = 0;
overflow = false;
for (int j = 0; j < segments.length; ++j) {
Segment<K,V> seg = segmentAt(segments, j);
if (seg != null) {
sum += seg.modCount;
int c = seg.count;
if (c < 0 || (size += c) < 0)
overflow = true;
}
}
if (sum == last)
break;
last = sum;
}
} finally {
if (retries > RETRIES_BEFORE_LOCK) {
for (int j = 0; j < segments.length; ++j)
segmentAt(segments, j).unlock();
}
}
return overflow ? Integer.MAX_VALUE : size;
}
多线程题目
多线程编程题
https://www.cnblogs.com/zhihuayun/p/6861083.html
编程大题
https://www.cnblogs.com/cielosun/p/6659678.html