JDK源码——java.util.concurrent(五)

测试代码:
https://github.com/kevindai007/springboot_houseSearch/tree/master/src/test/java/com/kevindai/juc

CountDownLatch

咱们先从demo中看CountDownLatch的使用方法和特点

public class SemaphoreTest {
    public static void main(String[] args) throws InterruptedException {
        final Semaphore semaphore = new Semaphore(10);
        final AtomicInteger number = new AtomicInteger();
        for (int i = 0; i < 100; i++) {
            Runnable runnable = new Runnable() {
                public void run() {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {}
                    try {
                        semaphore.acquire();
                        number.incrementAndGet();
                    } catch (InterruptedException e) {}
//                    finally {
//                        semaphore.release();
//                    }
                }
            };
            Thread thread = new Thread(runnable);
            thread.start();
        }
        Thread.sleep(10000);
        System.out.println("共" + number.get() + "个线程获得到信号");
        //System.exit(0);
    }
}

从上面的用法可以看到,ConutDownLatch是用在等待一组线程完成后,另外一个线程开始运行

CountDownLatch内部也有一个AQS的实现

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

    private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;
        //设置state为count的数量,可简单理解为锁的可重入次数
        Sync(int count) {
            setState(count);
        }

        //获取剩余count数量
        int getCount() {
            return getState();
        }

        //AQS的实现,acquire检查state值
        protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }

        //AQS的实现,释放资源自旋+cas设置state值  
        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;
            }
        }
    }

能明显看出,这里的Sync实现了AQS的共享模式;共享模式的大致流程如下:
acquire:
if(tryAcquireShared<0)
加入等待队列
release:
if(tryReleaseShared)
将队列所有节点unpark(独占模式是release一个)

CountDownLatch的剩余方法如下

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

CountDownLatch的代码还是比较简单的,构造函数传入count数,内部类sync通过count设置state值,响应中断的await用来acquire,检查state的值,不是0就加入AQS的同步等待队列,当有线程调用countDown时递减state值,一直到有线程递减到state值为0时,唤醒AQS等待队列所有线程.

Semaphore

一样,咱们首先通过一个demo来看看Semaphore的用法和特点

public class SemaphoreTest {
    public static void main(String[] args) throws InterruptedException {
        final Semaphore semaphore = new Semaphore(10);
        final AtomicInteger number = new AtomicInteger();
        for (int i = 0; i < 100; i++) {
            Runnable runnable = new Runnable() {
                public void run() {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {}
                    try {
                        semaphore.acquire();
                        number.incrementAndGet();
                    } catch (InterruptedException e) {}
                }
            };
            Thread thread = new Thread(runnable);
            thread.start();
        }
        Thread.sleep(10000);
        System.out.println("共" + number.get() + "个线程获得到信号");
        //System.exit(0);
    }
}

由这个demo我们可以简单的知道Semaphore的特点,Semaphore设定一个信号量,获取到信号量的线程能够正常运行,而获取不到的,在则会阻塞.

下面咱们从源码上来分析分析Semaphore

    public Semaphore(int permits) {
        //默认非公平模式
        sync = new NonfairSync(permits);
    }
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

可以看到Semaphore也分公平模式和非公平模式, 与ReentrantLock很相似,公平模式就是所有节点在要获取资源时都进去等待队列去排队获取;而非公平模式在获取资源是会直接尝试获取,如果获取不到,再进入条件队列中等待

在Semaphore中也有一个AQS的内部实现Sync

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

        Sync(int permits) {
            //设置state为permits的数量,可理解为可获取资源的次数
            setState(permits);
        }
        //返回剩余可获取资源次数
        final int getPermits() {
            return getState();
        }
        //非公平模式共享方式获取资源
        final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                //剩余许可数量
                int available = getState();
                int remaining = available - acquires;
                //如果remaining小于0则获取许可失败;如果remaining大于0,则cas设置剩余许可
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }
        //AQS共享模式释放资源的实现(代码很简单,不做分析)
        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;
            }
        }
        //这里是获取所有可用的许可量,并把许可数量置为0
        final int drainPermits() {
            for (;;) {
                int current = getState();
                if (current == 0 || compareAndSetState(current, 0))
                    return current;
            }
        }
    }

这里的Sync的实现很简单,咱们看看其实现类

    //非公平实现
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = -2694183684443567898L;

        NonfairSync(int permits) {
            super(permits);
        }
        //AQS共享模式获取资源的实现
        protected int tryAcquireShared(int acquires) {
            //此方法在Sync中实现,上面有讲到
            return nonfairTryAcquireShared(acquires);
        }
    }

    //公平模式实现
    static final class FairSync extends Sync {
        private static final long serialVersionUID = 2014338818796000944L;

        FairSync(int permits) {
            super(permits);
        }
        //AQS共享模式获取资源
        protected int tryAcquireShared(int acquires) {
            for (;;) {
                //如果有等待的线程,那么返回-1加入等待队列
                if (hasQueuedPredecessors())
                    return -1;
                //如果没有等待的线程,那么尝试获取资源
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }
    }

其实到这Semaphore的核心已经了解了,其他的方法都是一些封装,咱们一起来看看

/** 
调用AQS响应中断的Acquire 
 */  
public void acquire() throws InterruptedException {  
    sync.acquireSharedInterruptibly(1);  
}  
/** 
这个不响应中断的Acquire  
 */  
public void acquireUninterruptibly() {  
    sync.acquireShared(1);  
}  
/** 
直接调用sync的非公平Acquire,如果你构造的时候使用的是公平模式,肯定会打破公平 
 */  
public boolean tryAcquire() {  
    return sync.nonfairTryAcquireShared(1) >= 0;  
}  
/** 
响应中断跟超时的Acquire 
 */  
public boolean tryAcquire(long timeout, TimeUnit unit)  
    throws InterruptedException {  
    return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));  
}  
/** 
直接release一个许可 
 */  
public void release() {  
    sync.releaseShared(1);  
}  
/** 
响应Acquire指定数量的许可 
 */  
public void acquire(int permits) throws InterruptedException {  
    if (permits < 0) throw new IllegalArgumentException();  
    sync.acquireSharedInterruptibly(permits);  
}  
/** 
不响应中断的Acquire指定数量的许可 
 */  
public void acquireUninterruptibly(int permits) {  
    if (permits < 0) throw new IllegalArgumentException();  
    sync.acquireShared(permits);  
}  
/** 
非公平的Acquire指定数量的许可 
 */  
public boolean tryAcquire(int permits) {  
    if (permits < 0) throw new IllegalArgumentException();  
    return sync.nonfairTryAcquireShared(permits) >= 0;  
}  
/** 
响应中断和超时的Acquire指定数量的许可 
 */  
public boolean tryAcquire(int permits, long timeout, TimeUnit unit)  
    throws InterruptedException {  
    if (permits < 0) throw new IllegalArgumentException();  
    return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));  
}  
/** 
release指定数量的许可 
 */  
public void release(int permits) {  
    if (permits < 0) throw new IllegalArgumentException();  
    sync.releaseShared(permits);  
}  
/** 
查询许可量 
 */  
public int availablePermits() {  
    return sync.getPermits();  
}  
/** 
Acquire所有可用的许可并返回许可量 
 */  
public int drainPermits() {  
    return sync.drainPermits();  
}  
/** 
扣减指定数量的许可,会导致许可量为负数,使用的时候注意,自己可以定义个子类看看 
 */  
protected void reducePermits(int reduction) {  
    if (reduction < 0) throw new IllegalArgumentException();  
    sync.reducePermits(reduction);  
}  
/** 
验证是否是公平 
 */  
public boolean isFair() {  
    return sync instanceof FairSync;  
}  
/** 
调用AQS检查队列是否还有等待节点 
 */  
public final boolean hasQueuedThreads() {  
    return sync.hasQueuedThreads();  
}  
/** 
返回AQS中节点数量 
 */  
public final int getQueueLength() {  
    return sync.getQueueLength();  
}  
/** 
返回AQS同步等待队列所有等待Acquire的数量 
 */  
protected Collection<Thread> getQueuedThreads() {  
    return sync.getQueuedThreads();  
}  

可以看到这些方法都是一些很简单的封装没什么内容.

Semaphore很简单,就是设置信号量让获取到信号量的资源能够继续运行,获取不到的继续等待,可用于控制同时运行线程数量(感觉和线程池有那么点点相似).

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值