并发限流——Semaphore类

目录

 

1 初识Semaphore

1.1 动态增加许可证数量

1.2 公平和非公平方式获取许可证

2 常用方法

2.1 acquireUninterruptibly() 和 acquireUninterruptibly(int permits) 方法

2.2 drainPermits() 和 availablePermits() 方法

2.3 getQueueLength() 和 hasQueuedThreads() 方法

2.4 尝试获取许可证


1 初识Semaphore

Semaphore类是Concurrent包下的并发编程类,功能是并发限流,比如有很多线程要访问某个资源,但是由于计算能力有限,如果这些线程全部都去获取资源的话,系统会崩溃的,那么此时可以限制同时访问资源的线程数,这样减轻压力。

Semaphore semaphore = new Semaphore(int permits); //创建此类,初始化许可证数量。

public void acquire(); 获取一个许可证。

public void release(); 释放一个许可证。

public void acquire(int permits); 获取permits 个许可证。

public void release(int permits); 释放permits 个许可证。

许可证数量有限,必须先获取许可证,才能继续执行代码,如果许可证已经被用完了,就阻塞等待,直到有线程释放了许可证,再去获取许可证,执行完后,还要释放许可证(归还许可证)。

举个例子去说明,1个图书馆,3个学生,由于图书馆只有2个座位,因此任何时刻,只允许最多2个学生同时在图书馆读书,只有等某个学生读完了离开了,其它的学生才能去拿到座位读书。这种情况就是典型的限流。

图书馆类:

public class Library {
    private Semaphore semaphore = new Semaphore(2);

    public void ReadBook(int time) throws InterruptedException {
        semaphore.acquire();
        System.out.println(Thread.currentThread().getName() + "正在读.....");
        Thread.sleep(time);
        System.out.println(Thread.currentThread().getName() + "已经读完了");
        semaphore.release();
    }
}

学生类:

public class Student extends Thread {
    private Library library;
    private int time;
    public Student(Library library, int time){
        this.library = library;
        this.time = time;
    }
    @Override
    public void run() {
        super.run();
        try {
            library.ReadBook(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

测试代码:

public class CreateTest {
    public static void main(String[] args){
        Library library = new Library();
        /**
          * 学生1读书6秒
          */
        Student studentOne = new Student(library, 6000);
        /**
          * 学生2读书2秒
          */
        Student studentTwo = new Student(library, 2000);
        /**
          * 学生3读书1秒
          */
        Student studentThree = new Student(library, 1000);
        studentOne.setName("学生1");
        studentTwo.setName("学生2");
        studentThree.setName("学生3");
        studentOne.start();
        studentTwo.start();
        studentThree.start();
    }
}

运行结果:

  

1.1 动态增加许可证数量

一般初始化了许可证的数量,就不再改变了,但是有时需要动态地增加许可证,怎么办呢?

正常情况下,我们获取了多少个许可证,用完之后,就会释放掉多少个许可证。但是假如我们获取了2个许可证,但是释放了3个许可证,那么许可证的数量就会增加1。因此,动态增加许可证的方法就是:执行更多的release()方法。下面举例说明:

    public Semaphore semaphore = new Semaphore(2);
    public static void main(String[] args){
        CreateTest createTest = new CreateTest();
        try {
            createTest.semaphore.acquire();
            System.out.println("可用的许可证数量:" + createTest.semaphore.availablePermits());
            createTest.semaphore.release();
            createTest.semaphore.release();
            System.out.println("可用的许可证数量:" + createTest.semaphore.availablePermits());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

运行结果:

  

1.2 公平和非公平方式获取许可证

public Semaphore(int permits, boolean fair); // fair参数是用于设置公平还是非公平方式,true表示公平,false表示非公平。

公平方式:即终生平等,先来先得。

非公平方式:可能会出现抢占情况,因此不是公平的,默认使用非公平方式,效率比公平方式高。

2 常用方法

2.1 acquireUninterruptibly() 和 acquireUninterruptibly(int permits) 方法

public void acquireUninterruptibly(); //功能上与acquire()类似,用于获取一个许可证,不同之处在于,如果线程用此方法去获取许可证时,发现没有了,就会阻塞,阻塞期间不允许被中断。

public void acquireUninterruptibly(int permits); //获取permits个许可证。

2.2 drainPermits() 和 availablePermits() 方法

public int drainPermits(); //获取可用的许可证数量,但是获取后会将可用许可证的数量置为0。

public int availablePermits(); //仅仅是获取可用的许可证数量。

Semaphore semaphore = new Semaphore(2);
semaphore.acquire();
System.out.println("可用的许可证数量:" + semaphore.drainPermits());
System.out.println("可用的许可证数量:" + semaphore.availablePermits());

运行结果:

  

2.3 getQueueLength() 和 hasQueuedThreads() 方法

public final int getQueueLength(); //返回等待获取许可证的线程数量。

public final boolean hasQueuedThreads(); //是否有线程在等待获取许可证。

2.4 尝试获取许可证

1、public boolean tryAcquire(); //尝试获取1个许可证,获取成功就返回true,如果获取不到,就返回false,不阻塞。

2、public boolean tryAcquire(long timeout, TimeUnit unit); //unit是时间单位,timeout是时间长度,在此时间内尝试去获取1个许可证,如果成功就返回true,失败返回false。

3、public boolean tryAcquire(int permits); //尝试获取permits个许可证,成功返回true,失败返回false,不阻塞。

4、public boolean tryAcquire(int permits, long timeout, TimeUnit unit); //尝试在规定时间内获取permits个许可证,成功返回true,失败返回false。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值