线程的并发工具类(4)---Semaphore

我就是我 2023-07-15 13:22 116阅读 0赞

Semaphore的用法

        • 1 .Semaphore介绍
            • 1.1 用法场景
            • 1.2 原理
        • 2 .Semaphore使用

1 .Semaphore介绍

Semaphore:主要是用于流量控制。
作用:控制同时访问某个特定资源的线程数量,用于流量控制。

1.1 用法场景

最熟悉的场景就是数据库链接池的实现。在链接池的链接都被占用时,就会一直在等待憋的线程释放数据库链接资源,直到池中有可用链接。

1.2 原理

在初始化Semaphore实例的时候,同时会初始化许可证的数量N new Semaphore(N)。使用acquire()方法调用,调用成功后数量减1。当数量减为0时,会一直在acquire()这里等待,直到有可用许可证。使用完成后调用release()方法归还。

2 .Semaphore使用

Semaphore功能的实现主要是有两个方法配合acquire()和release()。acquire()是获取许可,release()是归还许可。
Semaphore有两种模式,公平模式和非公平模式。公平模式就是调用acquire的顺序就是获取许可证的顺序,遵循先进先出(FIFO);而非公平模式是抢占式的,也就是有可能一个新的获取线程恰好在一个许可证释放时得到了这个许可证,而前面还有等待的线程,默认是非公平模式。
两个构造方法Semaphore(int permits)和Semaphore(int permits, boolean fair)。permits为许可证数量,fair设置是否是先进先出。
看下具体实现:
SimulateCollection模拟一个数据库链接的实现。

  1. import java.util.Collection;
  2. import java.util.Iterator;
  3. public class SimulateCollection implements Collection {
  4. @Override
  5. public int size() {
  6. return 0;
  7. }
  8. ...
  9. }

UseSemaphore模拟一个数据库链接池的实现。

  1. import java.util.LinkedList;
  2. import java.util.concurrent.Semaphore;
  3. /** * UseSemaphore:模拟数据库链接池的实现 */
  4. public class UseSemaphore {
  5. LinkedList<SimulateCollection> pool = new LinkedList<>();
  6. private Semaphore useful;
  7. private Semaphore already;
  8. // public UseSemaphore(Semaphore useful,Semaphore already){
  9. // this.useful = useful;
  10. // this.already = already;
  11. // }
  12. public UseSemaphore(int linkNum) {
  13. if(linkNum<=0){
  14. linkNum=6;
  15. }
  16. this.useful = new Semaphore(linkNum);
  17. this.already = new Semaphore(0);
  18. }
  19. //获取数据库链接
  20. public SimulateCollection getCollection() throws InterruptedException {
  21. useful.acquire();
  22. SimulateCollection collection = null;
  23. synchronized (pool) {
  24. if (pool.size() > 0) {
  25. collection = pool.removeFirst();
  26. }
  27. }
  28. already.release();
  29. return collection;
  30. }
  31. //释放数据库链接资源
  32. public SimulateCollection releaseCollection(SimulateCollection collection) throws InterruptedException {
  33. already.acquire();
  34. synchronized (pool) {
  35. if (collection != null) {
  36. pool.addLast(collection);
  37. }
  38. }
  39. useful.release();
  40. return collection;
  41. }
  42. }

TestSemaPhore测试类:

  1. public class TestSemaPhore implements Runnable {
  2. private UseSemaphore useSemaphore;
  3. public TestSemaPhore(UseSemaphore useSemaphore){
  4. this.useSemaphore = useSemaphore;
  5. }
  6. @Override
  7. public void run() {
  8. try {
  9. System.out.println("线程"+Thread.currentThread().getName()+"开始获取数据库链接");
  10. long start = System.currentTimeMillis();
  11. SimulateCollection simulateCollection = useSemaphore.getCollection();
  12. long end = System.currentTimeMillis();
  13. System.out.println("线程"+Thread.currentThread().getName()+"数据库链接获取成功,耗时"+(end-start)+"ms");
  14. System.out.println("线程"+Thread.currentThread().getName()+"开始工作。。。");
  15. Thread.sleep(500);
  16. System.out.println("线程"+Thread.currentThread().getName()+"工作完成释放链接");
  17. useSemaphore.releaseCollection(simulateCollection);
  18. } catch (InterruptedException e) {
  19. e.printStackTrace();
  20. }
  21. }
  22. public static void main(String[] args) {
  23. TestSemaPhore testSemaPhore = new TestSemaPhore(new UseSemaphore(2));
  24. for (int i=0;i<6;i++){
  25. new Thread(testSemaPhore).start();
  26. }
  27. }
  28. }

运行结果:

  1. 线程Thread-0开始获取数据库链接
  2. 线程Thread-1开始获取数据库链接
  3. 线程Thread-0数据库链接获取成功,耗时0ms
  4. 线程Thread-1数据库链接获取成功,耗时0ms
  5. 线程Thread-0开始工作。。。
  6. 线程Thread-1开始工作。。。
  7. 线程Thread-2开始获取数据库链接
  8. 线程Thread-3开始获取数据库链接
  9. 线程Thread-4开始获取数据库链接
  10. 线程Thread-5开始获取数据库链接
  11. 线程Thread-1工作完成释放链接
  12. 线程Thread-0工作完成释放链接
  13. 线程Thread-2数据库链接获取成功,耗时504ms
  14. 线程Thread-2开始工作。。。
  15. 线程Thread-3数据库链接获取成功,耗时504ms
  16. 线程Thread-3开始工作。。。
  17. 线程Thread-2工作完成释放链接
  18. 线程Thread-3工作完成释放链接
  19. 线程Thread-4数据库链接获取成功,耗时1005ms
  20. 线程Thread-4开始工作。。。
  21. 线程Thread-5数据库链接获取成功,耗时1005ms
  22. 线程Thread-5开始工作。。。
  23. 线程Thread-4工作完成释放链接
  24. 线程Thread-5工作完成释放链接

发表评论

表情:
评论列表 (有 0 条评论,116人围观)

还没有评论,来说两句吧...

相关阅读

    相关 线并发工具

    Fork-Join 什么是分而治之? 规模为N的问题,N<阈值,直接解决,N>阈值,将N分解为K个小规模子问题,子问题互相对立,与原问题形式相同,将子问题的解合并得到