同步队列&锁的设计

节点状态

          #因超时或中断,该线程被取消
        /** 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

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chenxuezhou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值