关于aqs:Semaphore实战

8次阅读

共计 2642 个字符,预计需要花费 7 分钟才能阅读完成。

简介


Semaphore信号量计数器。和 CountDownLatch,CyclicBarrier 相似,是多线程合作的工具类,绝对于 join,wait,notify 办法应用起来简略高效。上面咱们次要看看它的用法吧!

实战


  • 限流。限度线程的并发数。

比方在一个零碎中同时只能保障 5 个用户同时在线。

import java.util.concurrent.Semaphore;

/**
 * @author:jiaolian
 * @date:Created in 2021-03-04 11:13
 * @description:Semaphore 限流
 * @modified By:* 公众号: 叫练
 */
public class LimitCurrnet {public static void main(String[] args) throws InterruptedException {
        // 定义 20 个线程,每次最多只能执行 5 个线程;
        Semaphore semaphore = new Semaphore(5);
        for (int i=0; i<20; i++) {new Thread(()->{
                try {
                    // 获取凭证
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName()+"登录胜利");
                    Thread.sleep(2000);
                    // 开释凭证
                    semaphore.release();
                    System.out.println(Thread.currentThread().getName()+"用户退出");
                } catch (InterruptedException e) {e.printStackTrace();
                }
            }).start();}
    }
}

如上代码所示:咱们定义了 20 个用户同时拜访零碎,Semaphore 参数是 5,示意同时只能有 5 个用户能够获取凭证,其余用户必须期待直到有在线用户退出。调用 semaphore.acquire()示意获取凭证,此时凭证数会减一,调用 semaphore.release()示意开释凭证,凭证数会加一,如果零碎中有期待的用户,操作此办法会告诉期待的一个用户获取凭证胜利,执行登录操作。最初打印 局部后果 如下:证实零碎最多能放弃 5 个用户同时在线。

留神:下面举出的这个案例,出个思考题:线程池是否能够实现呢?

  • 模仿 CyclicBarrier,CountDownLatch 重用!

Semaphore 能够轻松实现 CountDownLatch 计数器,CyclicBarrier回环屏障,还记得 CountDownLatch 用法么?它是个计数器,能够帮咱们统计线程执行工夫,罕用来测试多线程高并发执行接口效率,咱们上面用 Semaphore 模仿多线程主线程期待子线程执行结束再返回。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
/**
 * @author:jiaolian
 * @date:Created in 2021-03-01 21:04
 * @description:信号量测试
 * @modified By:* 公众号: 叫练
 */
public class SemaphoreTest {

    // 定义线程数量;
    private static final int THREAD_COUNT = 2;
    // 初始化信号量为 0,默认是非偏心锁
    private static Semaphore semaphore = new Semaphore(0,false);
    private static ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT);

    public static void main(String[] args) throws InterruptedException {for (int i=0; i<THREAD_COUNT; i++) {executorService.submit(()->{
                try {Thread.sleep(2000);
                } catch (InterruptedException e) {e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"执行");
                semaphore.release();});
        }
        // 获取 2 个信号量
        semaphore.acquire(2);
        System.out.println("主线程执行结束");
        executorService.shutdown();}
}

如上代码所示:咱们定义了 Semaphore 初始化信号量为 0,默认是非偏心锁,在主线程中用线程池提交 2 个线程,主线程调用 semaphore.acquire(2)示意须要获取两个信号量,但此时初始化信号量为 0,此时 AQS 中的 state 会是 0 -2=-2,state 值小于 0,所以主线程执行这句话会阻塞将其退出 AQS 同步队列,线程池两个线程期待 2 秒后会调用 semaphore.release()开释 2 个信号量,此时 AQS 中的 state 会自增到 0,会告诉主线程退出期待持续往下执行。执行后果如下图所示。

有没有发现 Semaphore 用法能够模仿 CountDownLatch,另外Semaphore 通过调用 acquire,release 办法,还能够实现 CyclicBarrier 性能!咱们不举例了。

实现原理


  • 相同点:实质上都是计数器,底层是依赖 AQS 操作 state 实现。
  • 异同点:CountDownLatch是共享锁实现,CyclicBarrier是独占锁实现,CountDownLatch通过调用 countDown 递加计数器只能应用一次,而 CyclicBarrier 通过调用 await 递加计数器能够达到“回环”反复的成果。Semaphore 也是共享锁实现,通过调用 release 计数器是递增的,通过设置信号量能够实现 CyclicBarrier,CountDownLatch 性能。

总结


明天咱们介绍了 Semaphore,整理出来心愿能对你有帮忙,写的比不全,同时还有许多须要修改的中央,心愿亲们加以斧正和点评,喜爱的请点赞加关注哦。 点关注,不迷路,我是【叫练 公众号 ,微信号【jiaolian123abc】 边叫边练。

正文完
 0