6 Java多线程:锁与AQS(下)

您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~
之前说过,AQS(抽象队列同步器)是Java锁机制的底层实现 。既然它这么优秀,是骡子是马,就拉出来溜溜吧 。
首先用重入锁来实现简单的累加,就像这样:
【6 Java多线程:锁与AQS(下)】/** * 用重入锁实现累加 * * @author 湘王 */public class MyLockTest {private final Lock lock = new ReentrantLock();private int value;public int getNext() {lock.lock();try {value++;} finally {lock.unlock();}return value;}public static void main(String[] args) {MyLockTest myLock = new MyLockTest();for (int i = 0; i < 5; i++) {new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println(myLock.getNext());}}}).start();}}}运行结果显示数据有重复:

6 Java多线程:锁与AQS(下)

文章插图
这么简单的计算都能出现重复,这肯定是无法接受的 。
再用独占锁来试试看:
/** * 利用AQS实现自定义独占锁 * * @author 湘王 */public class MyExclusiveLock implements Lock {@Overridepublic void lock() {}@Overridepublic void lockInterruptibly() throws InterruptedException {}@Overridepublic boolean tryLock() {return false;}@Overridepublic boolean tryLock(long time, TimeUnit unit) throws InterruptedException {return false;}@Overridepublic void unlock() {}@Overridepublic Condition newCondition() {return null;}}可以看到,实现lock接口,就需要实现若干自定义的接口 。然后以内部类继承AQS的方式,实现排他锁,昨天也说过,AQS中tryAcquire()和tryRelease()是一一对应的,也就是也管获?。?一个管释放,所以代码是:
/** * 内部类继承AQS的方式,实现排他锁 */private static class SyncHelper extends AbstractQueuedSynchronizer {private static final long serialVersionUID = -7666580981453962426L;/*** 第一个线程进来,拿到锁就返回true;后面的线程进来,拿不到锁就返回false*/@Overrideprotected boolean tryAcquire(int arg) {// 获取资源状态int state = getState();if (0 == state) {// 如果没有线程拿到资源的锁if (compareAndSetState(0, arg)) {// 保存当前持有同步锁的线程setExclusiveOwnerThread(Thread.currentThread());return true;}} else if (Thread.currentThread() == getExclusiveOwnerThread()) {// 如果当前线程再次进来 , state + 1,可重入// 如果这里没有这个判断,那么程序会卡死setState(state + arg);return true;}return false;}/*** 锁的获取和释放需要一一对应*/@Overrideprotected boolean tryRelease(int arg) {// 获取资源状态int state = getState();// 返回最后一个通过setExclusiveOwnerThread()方法设置过的线程 , 或者nullif (Thread.currentThread() != getExclusiveOwnerThread()) {throw new RuntimeException();}setState(state - arg);if (0 == state) {setExclusiveOwnerThread(null);return true;}return false;}protected Condition newCondition() {return new ConditionObject();}}然后再用AQS实现lock接口的方法:
/** * 利用AQS实现自定义独占锁 * * @author 湘王 */public class MyExclusiveLock implements Lock {private final SyncHelper synchepler = new SyncHelper();@Overridepublic void lock() {synchepler.acquire(1);}@Overridepublic void lockInterruptibly() throws InterruptedException {synchepler.acquireInterruptibly(1);}@Overridepublic boolean tryLock() {return synchepler.tryAcquire(1);}@Overridepublic boolean tryLock(long time, TimeUnit unit) throws InterruptedException {return synchepler.tryAcquireNanos(1, unit.toNanos(time));}@Overridepublic void unlock() {synchepler.release(1);}@Overridepublic Condition newCondition() {return synchepler.newCondition();}/*** 内部类继承AQS的方式,实现排他锁*/private static class SyncHelper extends AbstractQueuedSynchronizer {private static final long serialVersionUID = -7666580981453962426L;/*** 第一个线程进来 , 拿到锁就返回true;后面的线程进来,拿不到锁就返回false*/@Overrideprotected boolean tryAcquire(int arg) {// 获取资源状态int state = getState();if (0 == state) {// 如果没有线程拿到资源的锁if (compareAndSetState(0, arg)) {// 保存当前持有同步锁的线程setExclusiveOwnerThread(Thread.currentThread());return true;}} else if (Thread.currentThread() == getExclusiveOwnerThread()) {// 如果当前线程再次进来 , state + 1 , 可重入// 如果这里没有这个判断 , 那么程序会卡死setState(state + arg);return true;}return false;}/*** 锁的获取和释放需要一一对应*/@Overrideprotected boolean tryRelease(int arg) {// 获取资源状态int state = getState();// 返回最后一个通过setExclusiveOwnerThread()方法设置过的线程,或者nullif (Thread.currentThread() != getExclusiveOwnerThread()) {throw new RuntimeException();}setState(state - arg);if (0 == state) {setExclusiveOwnerThread(null);return true;}return false;}protected Condition newCondition() {return new ConditionObject();}}}

推荐阅读