美文网首页
高并发(10)- 线程并发工具类-Semaphore

高并发(10)- 线程并发工具类-Semaphore

作者: 残冬十九 | 来源:发表于2020-04-03 22:28 被阅读0次

    @[TOC](高并发(10)- 线程并发工具类-Semaphore)

    前言

    上篇文章讲解了线程的并发工具类之CyclicBarrier,本文就来讲解Semaphore并发工具类
    CyclicBarrier其实就是一个栅栏,需要等所有线程都到达栅栏才可以继续执行。
    Semaphore则是类似于信号量,有一个固定数量的凭证,线程来了拿走一个,用完还回来,当没有凭证可使用的时候,就开始等待

    什么是Semaphore

    Semaphore就是一个信号量。必须是获取他的线程释放,通常用来现在某些资源访问数量的场景使用。

    Semaphore执行图

    如上图所示,Semaphore定义了4个,当有线程进来时,需要通过acquire()方法取走一个凭证,当用完时,在通过release()方法将凭证返回。而当有多个线程涌进时,只有四个线程取到了凭证,其他的线程就需要等待其他线程release()返回凭证,然后执行。

    就如同生活中,去饭店吃饭,只有四张桌子,所以同时只允许四波客人吃饭,如果同时来了五批客人,服务员会让四批客人就做(获取凭证),第五批客人则是等待,因为这时候没有座位了,也就是没有凭证了,需要等有桌客人离坐(释放凭证),然后招呼第五批客人入座(获取凭证)。

    一个信号量有且仅有 3 种操作,且它们全部是原子的。
    初始化、增加和减少。
    增加可以为一个进程解除阻塞。
    减少可以让一个进程进入阻塞。

    Semaphore有什么用

    Semaphore有两个目的,第一个目的是多个共享资源互斥使用,第二目的是并发线程数的控制

    1.共享资源互斥使用

    例如我给我个共享资源加上了Semaphore等于1,所以肯定只有一个线程可以来使用这个资源,这就达到了共享资源互斥使用,

    2.并发线程数的控制

    比如我们有个线程池,需要限定并发线程的数量,我们就可以使用Semaphore来指定并发数量,所有的线程进来时都要获取凭证,取不到则等待,这就达到了并发线程数的控制效果。

    Semaphore的实现

    构造方法

    //创建指定长度的信号量,不公平的,
    public Semaphore(int permits);
    //创建指定长度的信号量,fair为true则是公平的
    public Semaphore(int permits,boolean fair);
    

    所谓的公平信号量是获得锁的顺序与调用semaphore.acquire()的顺序有关,但不代表100%地获得信号量,仅仅是在概率上能得到保证。而非公平信号量就是无关的了。

    Semaphore(int permits)构造方法是创建指定数量的信号量,属于不公平的信号量。

    Semaphore(int permits,boolean fair);构造方法是创建指定数量的信号量,fair为true则是公平的信号量,否则相反。

    普通方法

    //获取一个平成
    public void acquire();
    //获取指定数量的凭证,在提供这些凭证前一直将线程阻塞。比如n=2,就相当于占用了两个凭证
    public void acquire(int n);
    //释放一个凭证
    public void release();
    //释放n个凭证
    public void release(int n);
    //当前可用的凭证数
    public int availablePermits();;
    

    代码实现

    /**
     * @version 1.0
     * @Description SemaphoreDemo
     * @Author wb.yang
     * @Date 2020/4/3 7:21
     */
    public class SemaphoreDemo {
    
        /**
         * 创建指定长度信号量
         */
        private static final Semaphore SEMAPHORE = new Semaphore(2);
    
    
        /**
         * 工作线程
         */
        public static class SubThread implements Runnable {
    
            @Override
            public void run() {
                long id = Thread.currentThread().getId();
                try {
                    System.out.println("Thread_" + id + "准备开始获取凭证");
                    SEMAPHORE.acquire();
                    System.out.println("Thread_" + id + "获取到凭证执行输出,剩余凭证:" + SEMAPHORE.availablePermits());
                    Thread.sleep(1000);
                    System.out.println("Thread_" + id + "准备开始返回凭证");
                    SEMAPHORE.release();
                    System.out.println("Thread_" + id + "返回凭证输出,剩余凭证:" + SEMAPHORE.availablePermits());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) {
            for (int i = 0; i <= 3; i++) {
                Thread thread = new Thread(new SubThread());
                thread.start();
            }
        }
    
    }
    
    

    从代码中看出,我们定义了两个信号量,然后我们有一个工作线程。先获取了凭证,然后在执行业务逻辑,最后返回凭证,打印凭证数量。然后启动了四个线程,来测试这个代码。


    代码返回结果

    从代码结果可以看出,四个线程开始准备获取凭证,然后然后两个线程获取到了凭证,并且输出了剩余的凭证。然后剩下两个线程就在等待凭证,当哪两个线程执行完,释放了凭证,剩下的线程再去去获取凭证,然后执行之后的业务。

    相关文章

      网友评论

          本文标题:高并发(10)- 线程并发工具类-Semaphore

          本文链接:https://www.haomeiwen.com/subject/khilphtx.html