多线程之Semaphore

多线程之Semaphore

1 说明

Semaphore 信号量,用来限制能同时访问共享资源的线程上限.

public static void main(String[] args) {
     // 1. 创建 semaphore 对象
     Semaphore semaphore = new Semaphore(3);
    
     // 2. 10个线程同时运行
     for (int i = 0; i < 10; i++) {
         new Thread(() -> {
             // 3. 获取许可
             try {
                 semaphore.acquire();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
             try {
                 log.debug("running...");
                 sleep(1);
                 log.debug("end...");
             } finally {
                 // 4. 释放许可
                 semaphore.release();
             }
         }).start();
     }
 }

运行结果:

07:35:15.485 c.TestSemaphore [Thread-2] - running... 
07:35:15.485 c.TestSemaphore [Thread-1] - running... 
07:35:15.485 c.TestSemaphore [Thread-0] - running... 
07:35:16.490 c.TestSemaphore [Thread-2] - end... 
07:35:16.490 c.TestSemaphore [Thread-0] - end... 
07:35:16.490 c.TestSemaphore [Thread-1] - end... 
07:35:16.490 c.TestSemaphore [Thread-3] - running... 
07:35:16.490 c.TestSemaphore [Thread-5] - running... 
07:35:16.490 c.TestSemaphore [Thread-4] - running... 
07:35:17.490 c.TestSemaphore [Thread-5] - end... 
07:35:17.490 c.TestSemaphore [Thread-4] - end... 
07:35:17.490 c.TestSemaphore [Thread-3] - end... 
07:35:17.490 c.TestSemaphore [Thread-6] - running... 
07:35:17.490 c.TestSemaphore [Thread-7] - running... 
07:35:17.490 c.TestSemaphore [Thread-9] - running... 
07:35:18.491 c.TestSemaphore [Thread-6] - end... 
07:35:18.491 c.TestSemaphore [Thread-7] - end... 
07:35:18.491 c.TestSemaphore [Thread-9] - end... 
07:35:18.491 c.TestSemaphore [Thread-8] - running... 
07:35:19.492 c.TestSemaphore [Thread-8] - end... 

2 应用

  • Semaphore 限流,在访问高峰期时,让请求线程阻塞,高峰期过去再释放许可,当然它只适合限制单机 线程数量,并且仅是限制线程数,而不是限制资源数.

  • Semaphore 实现简单连接池,对比『享元模式』下的实现(用wait notify),性能和可读性显然更好.

class Pool {
     // 1. 连接池大小
     private final int poolSize;
     // 2. 连接对象数组
     private Connection[] connections;
     // 3. 连接状态数组 0 表示空闲, 1 表示繁忙
     private AtomicIntegerArray states;
     private Semaphore semaphore;
    
     // 4. 构造方法初始化
     public Pool(int poolSize) {
         this.poolSize = poolSize;
         // 让许可数与资源数一致
         this.semaphore = new Semaphore(poolSize);
         this.connections = new Connection[poolSize];
         this.states = new AtomicIntegerArray(new int[poolSize]);
         for (int i = 0; i < poolSize; i++) {
             connections[i] = new MockConnection("连接" + (i+1));
         }
     }
    
     // 5. 借连接
     public Connection borrow() {// t1, t2, t3
         // 获取许可
         try {
             semaphore.acquire(); // 没有许可的线程,在此等待
         } catch (InterruptedException e) {
             e.printStackTrace();
         }

         for (int i = 0; i < poolSize; i++) {
             // 获取空闲连接
             if(states.get(i) == 0) {
                 if (states.compareAndSet(i, 0, 1)) {
                     log.debug("borrow {}", connections[i]);
                     return connections[i];
                 }
             }
         }

         // 不会执行到这里
         return null;
     }
     // 6. 归还连接
     public void free(Connection conn) {
         for (int i = 0; i < poolSize; i++) {
             if (connections[i] == conn) {
                 states.set(i, 0);
                 log.debug("free {}", conn);
                 semaphore.release();
                 break;
             }
         }
     }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Semaphore是一个用于控制同时访问特定资源的线程数量的工具类。它可以用于限制同一时间内同时运行的线程数量,从而达到限流的效果。 Semaphore的构造函数有两个参数,第一个参数是许可数量,即允许同时访问的线程数量,第二个参数是公平性标志,如果设置为true,表示线程获取许可的顺序是按照线程调用acquire方法的顺序来确定的,否则是随机的。 Semaphore有两个主要方法: - acquire():获取一个许可,并减少许可数量,如果许可数量为0,则当前线程阻塞等待其他线程归还许可; - release():归还一个许可,并增加许可数量,如果有等待的线程,则其中一个线程会获取到许可。 代码示例: ```java import java.util.concurrent.Semaphore; public class SemaphoreExample { public static void main(String[] args) { int threadCount = 10; Semaphore semaphore = new Semaphore(5); // 设置最多允许5个线程同时运行 for (int i = 0; i < threadCount; i++) { new Thread(() -> { try { semaphore.acquire(); // 获取许可 System.out.println(Thread.currentThread().getName() + "开始执行"); Thread.sleep(1000); // 模拟执行 System.out.println(Thread.currentThread().getName() + "执行完毕"); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); // 释放许可 } }).start(); } } } ``` 解释: 上述代码中设置了最多允许5个线程同时运行,而实际创建了10个线程。在执行过程中,每个线程都会先去获取一个许可,只有获取到许可后才能执行其它操作。如果许可数量已经为0,则线程会进入阻塞等待状态,直到其它线程释放许可。当线程执行完毕后,会释放占用的许可,让其他线程可以继续执行。这样可以有效控制同时执行的线程数量,从而达到限流的效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值