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.
原文地址:https://www.cnblogs.com/yangyongjie/p/11020419.html