• Lock之ReentrantLock及实现生产者消费者和死锁


    Lock是顶层接口,它的实现逻辑并未用到synchronized,而是利用了volatile的可见性。ReentrantLock对了Lock接口的实现主要依赖了Sync,而Sync继承了

     AbstractQueuedSynchronizer(AQS)

     ReentrantLock:

    public class ReentrantLock implements Lock, java.io.Serializable {
        private static final long serialVersionUID = 7373984872572414699L;
        /** Synchronizer providing all implementation mechanics */
        private final Sync sync;
    
        /**
         * Base of synchronization control for this lock. Subclassed
         * into fair and nonfair versions below. Uses AQS state to
         * represent the number of holds on the lock.
         */
        abstract static class Sync extends AbstractQueuedSynchronizer {
            private static final long serialVersionUID = -5179523762034025860L;
    
            /**
             * Performs {@link Lock#lock}. The main reason for subclassing
             * is to allow fast path for nonfair version.
             */
            abstract void lock();
    
            /**
             * Performs non-fair tryLock.  tryAcquire is
             * implemented in subclasses, but both need nonfair
             * try for trylock method.
             */
            final boolean nonfairTryAcquire(int acquires) {
                final Thread current = Thread.currentThread();
                int c = getState();
                if (c == 0) {
                    if (compareAndSetState(0, acquires)) {
                        setExclusiveOwnerThread(current);
                        return true;
                    }
                }
                else if (current == getExclusiveOwnerThread()) {
                    int nextc = c + acquires;
                    if (nextc < 0) // overflow
                        throw new Error("Maximum lock count exceeded");
                    setState(nextc);
                    return true;
                }
                return false;
            }
    
            protected final boolean tryRelease(int releases) {
                int c = getState() - releases;
                if (Thread.currentThread() != getExclusiveOwnerThread())
                    throw new IllegalMonitorStateException();
                boolean free = false;
                if (c == 0) {
                    free = true;
                    setExclusiveOwnerThread(null);
                }
                setState(c);
                return free;
            }
    
            protected final boolean isHeldExclusively() {
                // While we must in general read state before owner,
                // we don't need to do so to check if current thread is owner
                return getExclusiveOwnerThread() == Thread.currentThread();
            }
    
            final ConditionObject newCondition() {
                return new ConditionObject();
            }
    
            // Methods relayed from outer class
    
            final Thread getOwner() {
                return getState() == 0 ? null : getExclusiveOwnerThread();
            }
    
            final int getHoldCount() {
                return isHeldExclusively() ? getState() : 0;
            }
    
            final boolean isLocked() {
                return getState() != 0;
            }
    
            /**
             * Reconstitutes this lock instance from a stream.
             * @param s the stream
             */
            private void readObject(java.io.ObjectInputStream s)
                throws java.io.IOException, ClassNotFoundException {
                s.defaultReadObject();
                setState(0); // reset to unlocked state
            }
        }
    }

    在AQS中,定义了一个volatile int state 变量作为共享资源。

     /**
         * The synchronization state.
         */
        private volatile int state;

    如果线程获取此共享资源失败,则进入同步FIFO队列中等待;如果成功获取资源就执行临界区代码。执行完释放资源时,会通知同步队列中的等待线程来获取资源后出对并执行。

    看其lock方法:

    首先默认构造是非公平锁,所谓的公平锁就是先等待的线程先获得锁

       public ReentrantLock() {
            sync = new NonfairSync();
        }

    NonfairSync:

    /**
         * Sync object for non-fair locks
         */
        static final class NonfairSync extends Sync {
            private static final long serialVersionUID = 7316153563782823691L;
    
            /**
             * Performs lock.  Try immediate barge, backing up to normal
             * acquire on failure.
             */
            final void lock() {
                if (compareAndSetState(0, 1))   //compareAndSetState(int expect, int update)
                    setExclusiveOwnerThread(Thread.currentThread());
                else
                    acquire(1);
            }
    
            protected final boolean tryAcquire(int acquires) {
                return nonfairTryAcquire(acquires);
            }
        }

    ReentrantLock:

        public void lock() {
            sync.lock();
        }

    所以,默认执行的是NonfairSync中的lock()实现,利用Unsafe类的CAS,期望state值为0时将其值设为1,返回是否成功

        protected final boolean compareAndSetState(int expect, int update) {
            // See below for intrinsics setup to support this
            return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
        }

    因此ReentrantLock的lock()方法只有在state为0时才能获得锁,并将state设为1。这样其他线程就无法获取锁,只能等待。

    由于ReentrantLock是可重入锁,即在获得锁的情况下,可以再次获得锁。并且线程可以进入任何一个它已经拥有的锁所同步着的代码块。若在没有释放锁的情况下,

    再次获得锁,则state加1,在释放资源时,state减1,因此Lock获取多少次锁就要释放多少次锁,直到state为0。

    Conditon中的await()对应Object的wait(),Condition中的signal()对应Object的notify(),Condition中的signalAll()对应Object的notifyAll()

    两个线程交替执行例子(同理生产者消费者也是这样交替执行)

    package com.yang.spbo.other.lock;
    
    import java.util.concurrent.LinkedBlockingDeque;
    import java.util.concurrent.ThreadFactory;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicInteger;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * A,B两个线程交替执行
     * 〈功能详细描述〉
     *
     * @author 17090889
     * @see [相关类/方法](可选)
     * @since [产品/模块版本] (可选)
     */
    public class ConditionService {
        private ReentrantLock lock = new ReentrantLock();
        /**
         * 两个线程所以创建两个condition
         */
        private Condition A = lock.newCondition();
        private Condition B = lock.newCondition();
    
        private int number = 1;
    
        private boolean flag = false;
    
        private void executeA() {
            while (number < 100) {
                try {
                    lock.lock();
                    if (!flag) {
                        System.out.println("A等待");
                        A.await();
                    }
                    System.out.println("A " + number);
                    number++;
                    flag = false;
                    System.out.println("B唤醒");
                    B.signal();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
    
        }
    
        private void executeB() {
            while (number < 100) {
                try {
                    lock.lock();
                    if (flag) {
                        System.out.println("B等待");
                        B.await();
                    }
                    System.out.println("B " + number);
                    number++;
                    flag = true;
                    System.out.println("A唤醒");
                    A.signal();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
    
        }
    
        public static void main(String[] args) {
            final ConditionService cs = new ConditionService();
            ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 1, TimeUnit.MINUTES, new LinkedBlockingDeque<Runnable>(1000), new MyThreadFactory("conditionService"));
    
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                    cs.executeA();
                }
            });
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                    cs.executeB();
                }
            });
        }
    
        static class MyThreadFactory implements ThreadFactory {
            /**
             * 线程名字前缀
             */
            private String namePrefix;
    
            private AtomicInteger id = new AtomicInteger(1);
    
            public MyThreadFactory(String namePrefix) {
                this.namePrefix = namePrefix;
            }
    
            @Override
            public Thread newThread(Runnable r) {
                String threadName = namePrefix + "-worker-" + id.getAndIncrement();
                Thread thread;
                thread = new Thread(r, threadName);
                return thread;
            }
        }
    }

    运行结果:

    conditionService-worker-1
    A等待
    conditionService-worker-2
    B 1
    A唤醒
    B等待
    A 2
    B唤醒
    A等待
    B 3
    A唤醒
    B等待
    A 4
    B唤醒
    A等待
    B 5
    A唤醒
    B等待
    A 6

    ReentrantLock实现死锁:

    /**
    * ReentrantLock实现死锁
    * 〈功能详细描述〉
    *
    * @author 17090889
    * @see [相关类/方法](可选)
    * @since [产品/模块版本] (可选)
    */
    public class DeadLockTest {
        private static ReentrantLock lock1 = new ReentrantLock();
        private static ReentrantLock lock2 = new ReentrantLock();
    
        public static void main(String[] args) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    lock1.lock();
                    try {
                        Thread.sleep(1000);
                        lock2.lock();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        lock1.unlock();
                    }
                }
            }).start();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    lock2.lock();
                    try {
                        Thread.sleep(1000);
                        lock1.lock();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        lock2.unlock();
                    }
    
                }
            }).start();
        }
    }
    分析过程:
    1.
    c:Program FilesJavajdk1.7.0_79in>jps
    7996 Main
    3960 Jps
    8396 Launcher
    5568 Launcher
    1204
    8212 Bootstrap
    396 ProfilerServer
    8036 DeadLockTest
     
    2.c:Program FilesJavajdk1.7.0_79in>jstack 8036
    Found one Java-level deadlock:
    =============================
    "Thread-1":
      waiting for ownable synchronizer 0x00000007d5e6f5c0, (a java.util.concurrent.l
    ocks.ReentrantLock$NonfairSync),
      which is held by "Thread-0"
    "Thread-0":
      waiting for ownable synchronizer 0x00000007d5e6f5f0, (a java.util.concurrent.l
    ocks.ReentrantLock$NonfairSync),
      which is held by "Thread-1"

    Java stack information for the threads listed above:
    ===================================================
    "Thread-1":
            at sun.misc.Unsafe.park(Native Method)
            - parking to wait for  <0x00000007d5e6f5c0> (a java.util.concurrent.lock
    s.ReentrantLock$NonfairSync)
            at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
            at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInt
    errupt(AbstractQueuedSynchronizer.java:834)
            at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(A
    bstractQueuedSynchronizer.java:867)
            at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(Abstrac
    tQueuedSynchronizer.java:1197)
            at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLo
    ck.java:214)
            at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:290)

            at deadLock.DeadLockTest$2.run(DeadLockTest.java:38)
            at java.lang.Thread.run(Thread.java:745)
    "Thread-0":
            at sun.misc.Unsafe.park(Native Method)
            - parking to wait for  <0x00000007d5e6f5f0> (a java.util.concurrent.lock
    s.ReentrantLock$NonfairSync)
            at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
            at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInt
    errupt(AbstractQueuedSynchronizer.java:834)
            at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(A
    bstractQueuedSynchronizer.java:867)
            at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(Abstrac
    tQueuedSynchronizer.java:1197)
            at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLo
    ck.java:214)
            at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:290)
     
            at deadLock.DeadLockTest$1.run(DeadLockTest.java:24)
            at java.lang.Thread.run(Thread.java:745)
     
    Found 1 deadlock.

     synchronized实现死锁:

    /**
    * synchronized实现死锁
    * 〈功能详细描述〉
    *
    * @author 17090889
    * @see [相关类/方法](可选)
    * @since [产品/模块版本] (可选)
    */
    public class DeadLockTest2 {
        private static Object obj1 = new Object();
        private static Object obj2 = new Object();
    
        public static void main(String[] args) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (obj1) {
                        System.out.println("thead1 get lock1");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        synchronized (obj2) {
                            System.out.println("thead1 get lock2");
                        }
                        System.out.println("thread1 end");
                    }
                }
            }, "thead1").start();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (obj2) {
                        System.out.println("thead2 get lock2");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        synchronized (obj1) {
                            System.out.println("thead2 get lock1");
                        }
                        System.out.println("thread2 end");
                    }
                }
            }, "thead2").start();
        }
    }
    Found one Java-level deadlock:
    =============================
    "thead2":
      waiting to lock monitor 0x000000000b15a7c8 (object 0x00000007d5e6f290, a java.
    lang.Object),
      which is held by "thead1"
    "thead1":
      waiting to lock monitor 0x000000000b1593d8 (object 0x00000007d5e6f2a0, a java.
    lang.Object),
      which is held by "thead2"

    Java stack information for the threads listed above:
    ===================================================
    "thead2":
            at deadLock.DeadLockTest2$2.run(DeadLockTest2.java:44)
            - waiting to lock <0x00000007d5e6f290> (a java.lang.Object)
            - locked <0x00000007d5e6f2a0> (a java.lang.Object)
            at java.lang.Thread.run(Thread.java:745)
    "thead1":
            at deadLock.DeadLockTest2$1.run(DeadLockTest2.java:27)
            - waiting to lock <0x00000007d5e6f2a0> (a java.lang.Object)
            - locked <0x00000007d5e6f290> (a java.lang.Object)
            at java.lang.Thread.run(Thread.java:745)

    Found 1 deadlock.
  • 相关阅读:
    loj2042 「CQOI2016」不同的最小割
    loj2035 「SDOI2016」征途
    luogu2120 [ZJOI2007]仓库建设
    luogu3195 [HNOI2008]玩具装箱TOY
    51nod 1069 Nim游戏 + BZOJ 1022: [SHOI2008]小约翰的游戏John(Nim游戏和Anti-Nim游戏)
    HDU 5723 Abandoned country(最小生成树+边两边点数)
    BZOJ 1497: [NOI2006]最大获利(最大权闭合图)
    51nod 1615 跳跃的杰克
    SPOJ 839 Optimal Marks(最小割的应用)
    UVa 11107 生命的形式(不小于k个字符串中的最长子串)
  • 原文地址:https://www.cnblogs.com/yangyongjie/p/11020419.html
Copyright © 2020-2023  润新知