开发者

多线程并发控制工具Semaphore的使用详解

目录
  • 1、Semaphore类
  • 2、基本概念
    • 2.1、信号量
    • 2.2、计数器
    • 2.3、公平性
  • 3、使用场景
    • 4、死锁
      • 4.1、条件
      • 4.2、解决策略
      • 4.3、联系
    • 总结

      当在多线程运行的场景,部分共享资源会存在资源的冲突和竞争,为了改善资源使用的方式,是否可以通过控制某个方法允许并发访问线程的数量?

      如下图所示:

      多线程并发控制工具Semaphore的使用详解

      Semaphore可以有效的缓解这个问题。

      1、Semaphore类

      在jdk中提供了一个Semaphore类(信号量)

      它提供了两个方法:

      • semaphore.acquire() 请求信号量,可以限制线程的个数,是一个正数,如果信号量是-1,就代表已经用完了信号量,其他线程需要阻塞了。
      • 第二个方法是semaphore.release(),代表是释放一个信号量,此时信号量的个数+1。

      2、基本概念

      2.1、信号量

      Semaphore 维护了一个计数器(许可的数量),表示可以同时访问某个资源的线程数量。线程通过申请许可来访问资源。

      2.2、计数器

      信号量的计数器可以被设置为一个初始值,该值表示许可的数量。每当一个线程获取许可时,计数器减一;当释放许可时,计数器加一。

      2.3、公平性

      Semaphore 可以配置为公平或非公平。公平的信号量遵循 FIFO(先入先出)原则,非公平android信号量则不保证获取的顺序。

      代码示例:

      import Java.util.concurrent.Semaphore;
      
      public class SemaphoreTest {
      
          public static void main(String[] arg编程s) {
              final DatabaseConnectionPool pool = new DatabaseConnectionPojsol(3);
      
              // 创建多个线程以模拟数据库连接
              Thread thread1 = new Thread(() -> pool.connect("Thread 1"));
              Thread thread2 = new Thread(() -> pool.connect("Thread 2"));
              Thread thread3 = new Thread(() -> pool.connect("Thread 3"));
              Thread thread4 = new Thread(() -> pool.connect("Thread 4"));
              Thread thread5 = new Thread(() -> pool.connect("Thread 5"));
      
      
              thread1.start();
              thread2.start();
              thread3.start();
              thread4.start();
              thread5.start();
      
          }
      }
      
      
      class DatabaseConnectionPool{
          private final Semaphore semaphore;
      
          DatabaseConnectionPool(int maxConnections) {
              this.semaphore = new Semaphore(maxConnections,true);
          }
      
          public void connect(String threadName) {
              try {
                  System.out.println(threadName + " is trying to connect.");
                  // 获取许可
                  semaphore.acquire();
                  System.out.println(threadName + " has connected to the database.");
                  // 模拟使用连接
                  Thread.sleep(5000); // 模拟数据库操作
              } catch (InterruptedException e) {
                  Thread.currentThread().interrupt();
              } finally {
                  // 释放许可
                  System.out.println(threadName + " is releasing the connection.");
                  semaphore.release();
              }
          }
      }

      代码解析

      1.Semaphore 的创建

      public DatabaseConnectionPool(int maxConnections) {
          this.semaphore = new Semaphore(maxConnections);
      }

      通过指定最大连接数来初始化信号量。

      2.获取连接

      semaphore.acquire()http://www.devze.com;

      线程尝试获取信号量的许可,如果没有可用的许可,则该线程会被阻塞,直到有许可可用。

      3.释放连接

      semaphore.release();

      访问完成后,线程释放许可,让其他线程能够访问。

      多线程模拟

      使用多个线程来模拟多个连接请求,只有 3 个线程能同时获取许可。

      3、使用场景

      • 控制并发访问某些资源,例如数据库连接、文件句柄等。
      • 限制同时执行的线程数量,以避免系统负载过大。

      4、死锁

      死锁是一种情况,其中两个或多个线程永远互相等待对方释放资源,从而导致程序无法继续执行。

      了解更多死锁知识,可参考:有关Java死锁和活锁的联系

      4.1、条件

      1. 互斥条件:至少有一个资源处于非共享模式,即某一时刻只能被一个线程使用。
      2. 保持并等待条件:一个线程保持至少一个资源并等待其他被其他线程占用的资源。
      3. 不剥夺条件:资源不能被强行夺走,只能由持有该资源的线程释放。
      4. 循环等待条件:存在一个线程的集合,使得每个线程都在等待下一个线程持有的资源。

      4.2、解决策略

      • 资源顺序申请:确保所有线程按照相同的顺序请求多个资源,这样可以避免循环等待。
      • 设置超时:在请求资源时设置超时,如果请求在一定时间内没有成功,线程应该释放它已持有的资源,有可能中断互斥条件。
      • 使用 tryLock tryAcquire:可使用 LockSemaphore 的尝试获取方法,在未能成功获取时,可以做适当的错误处理或重试,而不是静默等待。
      • 避免持有状态:尽量避免在一个线程中持有多个锁,或者隔离资源,以减少死锁风险。

      4.3、联系

      虽然 Semaphore 可以在某种情况下帮助减少发生死锁的机会,但它并不是解决死锁问题的直接手段。

      Semaphore 控制访问的方式可以导致某些设计上的改善,例如:

      1. 限制资源的同时访问Semaphore 可用于限制可同时访问某种资源的线程数量,从而减少复杂的资源使用模式。
      2. 避免持有过多的锁:通过合理设计线程的资源申请和释放逻辑,结合 Semaphore,可以减少因线程在持有多个资源时发生互斥和等待的可能性。

      总结

      Semaphore 是一个非常有用的并发控制工具,可以有效地控制对共享资源的访问。通过合理使用它,可以避免过多线程同时访问相同资源造成的竞争和冲突,从而提高并发程序的安全性和效率。

      以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.c编程客栈ppcns.com)。

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新开发

      开发排行榜