Java并发编程艺术(四) Java中的锁

1、Lock接口

Lock比synchronized多的特性

2、队列同步器

  • 同步器是实现锁的关键,在锁的实现中聚合同步器,利用同步器实现锁的语义。
  • 同步器是面向锁的实现者,简化了锁的实现方式,屏蔽了同步状态管理、线程的排队、等待与唤醒等底层操作。

2.1 队列同步器的接口与示例

  • 通过getState() setState() compareAndSetState() 修改状态。
同步器可重写方法
同步器模板方法
public class Mutex implements Lock {
    private static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -4387327721959839431L;

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

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

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

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

    private final Sync sync = new Sync();

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

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

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

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

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

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

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

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

2.2 队列同步器实现分析

同步队列

  • 同步器依赖内部的同步队列完成同步状态的管理,当前线程获取同步状态失败时,同步器会将当前线程以及等待状态等信息构造成一个节点并将其加入同步队列。
同步队列结构
  • 设置头结点不需要CAS保证。
  • 进入同步队列中,后续对线程进行中断操作时,线程不会从同步队列中移出。
  • 被阻塞线程主要由前驱节点出队或者阻塞线程被中断来实现。
独占式同步状态获取流程

3、重入锁

  • 对资源重复加锁,支持获取锁公平性选择。
  • 先请求的先满足则是公平的。
nofairTryAcquire
tryRelease

重入的实现

  • 线程再次获取,如果是当前占据锁的线程则可以再次成功获取。
  • 锁的释放,重复获取n次,就要释放n次。
  • 公平性可以通过同步队列中节点是否有前驱节点判断。但是非公平性锁效率通常会更高。

4、读写锁

  • 当写锁被获取到时,后续的读写操作都会被阻塞。
  • 读写锁维护一个读锁一个写锁。ReentrantReadWriteLock
ReentrantReadWriteLock
public class Cache {
    private static final Map    map = new HashMap();
    private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    private static final Lock                   r   = rwl.readLock();
    private static final Lock                   w   = rwl.writeLock();

    public static final Object get(String key) {
        r.lock();
        try {
            return map.get(key);
        } finally {
            r.unlock();
        }
    }

    public static final Object put(String key, Object value) {
        w.lock();
        try {
            return map.put(key, value);
        } finally {
            w.unlock();
        }
    }

    public static final void clear() {
        w.lock();
        try {
            map.clear();
        } finally {
            w.unlock();
        }
    }
}
读写状态的存储
  • 锁降级是持有写锁然后在获取读锁,再释放写锁,就会降级成读锁。

5、Condition接口

  • Condition接口提供了类似Object的监视器方法,与Lock配合可以实现等待通知模式。
  • 当前线程调用这些方法时,需要提前获取到Condition对象关联的锁。Condition对象是由Lock对象创建出来的。
public class ConditionUseCase {
    Lock      lock      = new ReentrantLock();
    Condition condition = lock.newCondition();

    public void conditionWait() throws InterruptedException {
        lock.lock();
        try {
            condition.await();
        } finally {
            lock.unlock();
        }
    }

    public void conditionSignal() throws InterruptedException {
        lock.lock();
        try {
            condition.signal();
        } finally {
            lock.unlock();
        }
    }
}
Condition方法
  • 一个Condition包含一个等待队列。
  • Condition使得Lock可以有一个同步队列和多个等待队列。
Condition等待
  • 节点从等待队列移动到同步队列,或从同步队列移动到等待队列。
加入等待队列
加入同步队列

你可能感兴趣的:(Java并发编程艺术(四) Java中的锁)