AQS之其他同步组件

Semaphore

允许多个线程同时访问。Syn类实现共享模式。
构造函数
permits:允许访问最大线程数
fair:指定是否是公平锁,默认false。

    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);
    }

sync父类AbstractQueuedSynchronizer的方法

   public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);//将节点加入等待队列(AbstractQueuedSynchronizer类方法)
    }

调用非公平锁重写的tryAcquireShared方法

  static final class NonfairSync extends Sync {
        private static final long serialVersionUID = -2694183684443567898L;

        NonfairSync(int permits) {
            super(permits);
        }
        protected int tryAcquireShared(int acquires) {
            return nonfairTryAcquireShared(acquires);
        }
    }

调用父类syn类nonfairTryAcquireShared方法

 final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                //获取当前可获取锁线程数
                int available = getState();
                //加算新的线程数
                int remaining = available - acquires;
                //如果无法获取或者CAS设置state成功,返回state
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }

释放锁(非公平锁)

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

调用sync父类AbstractQueuedSynchronizer的方法

 public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();//删除节点并唤醒其他线程
            return true;
        }
        return false;
    }

调用非公平锁重写的tryReleaseShared方法

        protected final boolean tryReleaseShared(int releases) {
            for (;;) {
                 //获取当前允许线程数
                int current = getState();
                //计算新的state
                int next = current + releases;
                if (next < current) // 溢出
                    throw new Error("Maximum permit count exceeded");
                //CAS设置state
                if (compareAndSetState(current, next))
                    return true;
            }
        }

获取剩余所有数量

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

CountDownLatch

允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行。
CountDownLatch通过一个计数器记录线程的数量,每个线程调用countDown方法后计数器会减一,当计数器为0时,等待的线程(即调用countDownLatch.await方法的线程)会被唤起。Syn类实现共享模式。
构造方法
指定计数器大小

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

await方法
调用此方法的线程会被阻塞,直到计数器为0或线程被中断

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

sync父类AbstractQueuedSynchronizer的acquireSharedInterruptibly方法

 public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);//将节点加入等待队列,将节点状态设置为共享
            //此方法会自旋,当队列中只有一个节点等待时,会等到state=0返回,当队列中有其他节点等待时,将前节点设为SIGNAL状态,再阻塞自己
    }

sync类重写tryAcquireShared方法

   //state=0 返回1(成功),否则返回-1
   protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }

countDown方法

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

sync父类AbstractQueuedSynchronizer的releaseShared方法

  public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();//唤醒队列中等待的线程(包括后继节点)
            return true;
        }
        return false;
    }

sync类重写tryReleaseShared方法

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;
                //CAS修改计数器
                if (compareAndSetState(c, nextc))
                    //当计数器不为0时返回false,不会唤醒队列中的线程
                    return nextc == 0;
            }
        }

使用场景:
1.某个线程调用await后等待n个线程执行完毕(new CountDownLatch(n))
2.多线程共享一个countDownLatch(new CountDownLatch(1)),n个线程调用await方法,主线程调用countDown(),n个线程同时被唤醒

CyclicBarrier

一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,所有阻塞的线程被唤醒。
数据结构
Generation代表每一轮Cyclibarrier的运行状况

    private static class Generation {
        Generation() {}             
        boolean broken;     //是否挂掉,默认为false      
    }

属性

    private final ReentrantLock lock = new ReentrantLock();
    private final Condition trip = lock.newCondition();
    private final int parties;
    private final Runnable barrierCommand;
    private Generation generation = new Generation();
    private int count;

构造方法
parties:表示线程数
barrierAction:所有线程都到达barrier时执行,可以为null
count:表示还未到达barrier的线程数,可以重置为parities

  public CyclicBarrier(int parties, Runnable barrierAction) {
        if (parties <= 0) throw new IllegalArgumentException();
        this.parties = parties;
        this.count = parties;
        this.barrierCommand = barrierAction;
    }

await方法
await() 调用dowait(time)

private int dowait(boolean timed, long nanos)
        throws InterruptedException, BrokenBarrierException,
               TimeoutException {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            final Generation g = generation;
            //当前Generation挂掉
            if (g.broken)
                throw new BrokenBarrierException();
            //线程中断,重置count
            if (Thread.interrupted()) {
                breakBarrier();
                throw new InterruptedException();
            }
            //计算当前剩余线程数
            int index = --count;
            //到达barrier
            if (index == 0) { 
                boolean ranAction = false;
                try {
                    final Runnable command = barrierCommand;
                    if (command != null)
                        command.run();
                    ranAction = true;
                    //开启下一轮
                    nextGeneration();
                    return 0;
                } finally {
                    if (!ranAction)
                        breakBarrier();
                }
            }
            //当前没有达到barrier,自旋
            for (;;) {
                try {
                    //没设定超时
                    if (!timed)
                        trip.await();
                    else if (nanos > 0L)
                        nanos = trip.awaitNanos(nanos);
                } catch (InterruptedException ie) {
                    if (g == generation && ! g.broken) {
                        breakBarrier();
                        throw ie;
                    } else {
                        // We're about to finish waiting even if we had not
                        // been interrupted, so this interrupt is deemed to
                        // "belong" to subsequent execution.
                        Thread.currentThread().interrupt();
                    }
                }
                if (g.broken)
                    throw new BrokenBarrierException();
                if (g != generation)
                    return index;
                if (timed && nanos <= 0L) {
                    breakBarrier();
                    throw new TimeoutException();
                }
            }
        } finally {
            lock.unlock();
        }
    }

CountDownLatch与CyclicBarrier

1.CountDownLatch只能使用一次,CyclicBarrier可以多次使用
2.CountDownLatch减计数,CyclicBarrier加计数
3.CountDownLatch是一个或多个线程等其他线程完成后再执行,CyclicBarrier是多个线程互相等待到同步点再一起执行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值