基于AQS的应用

ReentrantLock

//继承于AQS
public class ReentrantLock implements Lock, java.io.Serializable {
    private static final long serialVersionUID = 7373984872572414699L;
    /** Synchronizer providing all implementation mechanics */
    private final Sync sync;

    //默认非公平锁
    public ReentrantLock() {
        sync = new NonfairSync();
    }
    //也可以是公平锁
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
    
    public void lock() {
        sync.acquire(1);
    }

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

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

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

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

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

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

使用方式

Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
lock.lock();
try {
   while(条件判断表达式) {
      condition.wait();
}
// 处理逻辑
} finally {
   lock.unlock();
}

条件变量Condition
条件变量很大一个程度上是为了解决Object.wait/notify/notifyAll难以使用的问题。

public class ConditionObject implements Condition, java.io.Seria
lizable {
/** First node of condition queue. */
private transient Node firstWaiter;
/** Last node of condition queue. */
private transient Node lastWaiter;
public final void signal() {}
public final void signalAll() {}
public final void awaitUninterruptibly() {}
public final void await() throws InterruptedException {}
}
  1. Synchronized中,所有的线程都在同一个object的条件队列上等待。而
    ReentrantLock中,每个condition都维护了一个条件队列。
  2. 每一个Lock可以有任意数据的Condition对象,Condition是与Lock绑定的,所以就有Lock的公平性特性:如果是公平锁,线程为按照FIFO的顺序从Condition.await中释放,如果是非公平锁,那么后续的锁竞争就不保证FIFO顺序了。
  3. Condition接口定义的方法,await对应于Object.wait,signal对应于
    Object.notify,signalAll对应于Object.notifyAll。特别说明的是Condition的接口改变名称就是为了避免与Object中的wait/notify/notifyAll的语义和使用上混淆。

synchronized和ReentrantLock的比较

  • ① 两者都是可重⼊锁
    “可重⼊锁”概念是:⾃⼰可以再次获取⾃⼰的内部锁。⽐如⼀个线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象的锁的时候还是可以获取的,如果不可锁重⼊的话,就会造成死锁。同⼀个线程每次获取锁,锁的计数器都⾃增1,所以要等到锁的计数器下降为0时才能释放锁。
  • ② synchronized 依赖于 JVM ⽽ ReentrantLock 依赖于 API
    synchronized 是依赖于 JVM实现的,前⾯我们也讲到了 虚拟机团队在 JDK1.6 为 synchronized关键字进⾏了很多优化,但是这些优化都是在虚拟机层⾯实现的,并没有直接暴露给我们。
    ReentrantLock 是 JDK层⾯实现的(也就是 API 层⾯,需要 lock() 和 unlock() ⽅法配合try/finally语句块来完成),所以我们可以通过查看它的源代码,来看它是如何实现的。
  • ③ ReentrantLock ⽐ synchronized 增加了⼀些⾼级功能
    相⽐synchronized,ReentrantLock增加了⼀些⾼级功能。主要来说主要有三点:①等待可中断;②可实现公平锁;③可实现选择性通知(锁可以绑定多个条件)
    • ReentrantLock提供了⼀种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制。也就是说正在等待的线程可以选择放弃等待,改为处理其他事情。
    • ReentrantLock可以指定是公平锁还是⾮公平锁。⽽synchronized只能是⾮公平锁。所谓的公平锁就是先等待的线程先获得锁。
      ReentrantLock默认情况是⾮公平的,可以通过 ReentrantLock类的 ReentrantLock(boolean fair) 构造⽅法来制定是否是公平的。
    • synchronized关键字与wait()和notify()/notifyAll()⽅法相结合可以实现等待/通知机制,ReentrantLock类当然也可以实现,但是需要借助于Condition接⼝与newCondition()⽅法。

Semaphore
Semaphore(信号量)-允许多个线程同时访问: synchronized 和 ReentrantLock 都是⼀次只允许⼀个线程访问某个资源,Semaphore(信号量)可以指定多个线程同时访问某个资源。
基于CAS实现:

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

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

        final int getPermits() {
            return getState();
        }

        final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }

        protected final boolean tryReleaseShared(int releases) {
            for (;;) {
                int current = getState();
                int next = current + releases;
                if (next < current) // overflow
                    throw new Error("Maximum permit count exceeded");
                if (compareAndSetState(current, next))
                    return true;
            }
        }

        final void reducePermits(int reductions) {
            for (;;) {
                int current = getState();
                int next = current - reductions;
                if (next > current) // underflow
                    throw new Error("Permit count underflow");
                if (compareAndSetState(current, next))
                    return;
            }
        }

        final int drainPermits() {
            for (;;) {
                int current = getState();
                if (current == 0 || compareAndSetState(current, 0))
                    return current;
            }
        }
    }

基于AQS实现部分:

    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

    
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

    
    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

    
    public void acquireUninterruptibly() {
        sync.acquireShared(1);
    }

    
    public boolean tryAcquire() {
        return sync.nonfairTryAcquireShared(1) >= 0;
    }

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

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

    
    public void acquire(int permits) throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireSharedInterruptibly(permits);
    }

    
    public void acquireUninterruptibly(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireShared(permits);
    }

    
    public boolean tryAcquire(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        return sync.nonfairTryAcquireShared(permits) >= 0;
    }

    
    public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
        throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
    }

    
    public void release(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        sync.releaseShared(permits);
    }

CountDownLatch
CountDownLatch (倒计时器): CountDownLatch是⼀个同步⼯具类,⽤来协调多个线程之间的同步。这个⼯具通常⽤来控制线程等待,它可以让某⼀个线程等待直到倒计时结束,再开始执⾏。

public class CountDownLatch {
    /**
     * Synchronization control For CountDownLatch.
     * Uses AQS state to represent count.
     */
    private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;

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

        int getCount() {
            return getState();
        }

        protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }

        protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c - 1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
    }

    private final Sync sync;

    
    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }

    
    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

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

    
    public void countDown() {
        sync.releaseShared(1);
    }

    
    public long getCount() {
        return sync.getCount();
    }

   
    public String toString() {
        return super.toString() + "[Count = " + sync.getCount() + "]";
    }
}

CyclicBarrier
CyclicBarrier(循环栅栏): CyclicBarrier 和 CountDownLatch ⾮常类似,它也可以实现线程间的技术等待,但是它的功能⽐ CountDownLatch 更加复杂和强⼤。主要应⽤场景和CountDownLatch 类似。CyclicBarrier 的字⾯意思是可循环使⽤(Cyclic)的屏障(Barrier)。它要做的事情是,让⼀组线程到达⼀个屏障(也可以叫同步点)时被阻塞,直到最后⼀个线程到达屏障时,屏障才会开⻔,所有被屏障拦截的线程才会继续⼲活。
CyclicBarrier默认的构造⽅法是 CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调⽤await()⽅法告诉 CyclicBarrier 我已经到达了屏障,然后当前线程被阻塞。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值