并发编程 - 抽象锁AbstractQueuedSynchronizer

抽象锁

AbstractQueuedSynchronizer 很难去翻译这个词,抽象排队同步器?这里姑且叫抽象锁吧。

抽象锁只是一个抽象类,锁封装了一些锁的常规操作,包括信号量、倒数锁、可重入锁,内部代码都包含了抽象同步锁的实现类。

抽象同步锁用到了Unsafe类,Unsafe虽然在Java的基础包中,但是常规编程中根本无法调用。所以,目前阶段,可以将抽象同步锁看做是最底层的代码。

使用方式

在使用过程中会发现,IDE不会给任何提示,似乎没有任何抽象方法需要实现。

抽象同步锁确实不包含任何抽象函数,但是包含许多空函数,它希望开发人员有选择地,去重写这些函数。

比如,你希望锁调用acquireSharedInterruptibly()函数,那么就需要重写tryAcquireShared()函数,具体对应关系如下:

acquireSharedInterruptibly()  	——  tryAcquireShared()
acquireShared()  				——  tryAcquireShared()
releaseShared()  				——  tryReleaseShared()
 

acquireInterruptibly()  ——  tryAcquire()
acquire()  				——  tryAcquire()
release()  				——  tryRelease()

独占和共享

此类支持默认的 “独占模式” 和 “共享模式” 之一,或者二者都支持。

独占模式就像代码中的同步块,被 synchronized 修饰的函数,只有一个线程可以访问,其他线程试图获取该锁将无法取得成功;

而共享模式则用在一些共享数据上,就像阻塞队列,多个线程同时获取锁,多个线程都可能访问成功。

以文件读写锁为例:读取时,允许多个线程同时读,这是共享的;而写入的时候,只允许一个线程写,这时候就是独占的。

使用抽象同步锁实现线程同步(共享模式)

多个子线程先执行,然后主线程运行

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;

import com.sea.common.util.RandomUtils;

/**
 * 抽象锁的实现类一般设计为静态内部类,这里直接调用实现类,展示其功能
 * 我的需求明确,想要一个共享模式的锁,因此只实现tryAcquireShared()和tryReleaseShared()函数
 * 
 * @author ChenSS on 2018年2月3日
 */
class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = -860558119172333780L;

    Sync(int count) {
        setState(count);
    }

    /**
     * 此方法应该查询是否允许它在共享模式下获取对象状态
     */
    @Override
    protected int tryAcquireShared(int acquires) {
        return (getState() == 0) ? 1 : -1;
    }

    /**
     * 同倒计时锁功能类似,每次释放锁,锁的总量减一
     */
    @Override
    protected boolean tryReleaseShared(int releases) {
        for (;;) {
            int c = getState();
            if (c == 0)
                return false;
            int nextc = c - 1;
            if (super.compareAndSetState(c, nextc))
                return nextc == 0;
        }
    }
}

public class Test {
    public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
        int count = 5;
        Sync sync = new Sync(count);
        while (count-- > 0) {
            final int n = count;
            new Thread(() -> {
                try {
                    Thread.sleep(3000 + RandomUtils.nextLong(3000));
                    System.out.println("完成第" + n +"个初始化");
                    sync.releaseShared(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        sync.acquireShared(count);
        System.out.println("ok");
    }
}

官方Demo(独占模式)

收录于 jdk 文档内的案例

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

class Mutex implements Lock, java.io.Serializable {
    private static final long serialVersionUID = 7189538917731084955L;

    private static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 8005382235859105335L;

        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        @Override
        public boolean tryAcquire(int acquires) {
            assert acquires == 1; // Otherwise unused
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        @Override
        protected boolean tryRelease(int releases) {
            assert releases == 1; // Otherwise unused
            if (getState() == 0)
                throw new IllegalMonitorStateException();
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        public Condition newCondition() {
            return new ConditionObject();
        }
    }

    private final Sync sync = new Sync();

    @Override
    public void lock() {
        sync.acquire(1);
    }

    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    @Override
    public void unlock() {
        sync.release(1);
    }

    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }

    public boolean isLocked() {
        return sync.isHeldExclusively();
    }

    public boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }
}

public class Test {
    private final Mutex lock = new Mutex();

    /**
     * 多线程同时访问,每次只有一个函数执行
     */
    public void printLine() {
        final Mutex l = lock;
        l.lock();
        try {
            Thread.sleep(1000);
            System.out.println("-----------------------");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
        int count = 5;
        Test test = new Test();
        while (count-- > 0) {
            new Thread(() -> {
                test.printLine();
            }).start();
        }
    }
}

posted on 2018-02-16 18:11  疯狂的妞妞  阅读(380)  评论(0编辑  收藏  举报

导航