java并发-Semaphore

这篇具有很好参考价值的文章主要介绍了java并发-Semaphore。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

当下Java并发编程日益普及,而Semaphore是Java提供的一种功能强大的线程同步工具,可用于控制同时访问系统资源的线程数量。本篇博客将从Semaphore的简介、底层实现和应用场景等角度,深入探讨Semaphore的原理以及其实现和使用方法。

## 1、Semaphore的简介
Semaphore是一种计数器,用于控制同时访问资源的线程数量。它通过一个计数器来表达可用资源的数量,当有新线程需要访问该资源时,会先进行请求,然后进行P(proberen)操作,如果此时计数器的值为0,则线程就会被阻塞并进入等待队列中,等到其他线程释放资源后才重新获得控制权。而当线程释放资源时,则会进行V(verhogen)操作,将计数器的值加1,以通知其他线程可以继续请求访问资源。

Semaphore的构造方法有两个参数,分别表示初始的资源数量和是否为公平锁。如果将公平锁设置为true,则多个线程并发访问Semaphore时,会按照它们的请求顺序进行处理,即先请求的线程也会先获得资源。

Semaphore是一个典型的Java并发库类,位于java.util.concurrent包中。

## 2、Semaphore的底层实现
在Semaphore的底层实现中,它是基于AQS(AbstractQueuedSynchronizer)的同步器实现的。AQS是一个为JDK提供的一个框架,用于实现同步器,比如锁、Semaphore等,是基于队列的锁和同步器的实现框架。

Semaphore的底层实现主要基于两个方法:
- acquire():申请许可证,实际上就是P操作。
- release():释放许可证,实际上就是V操作。

在Semaphore的实现中,如果许可证数量大于0,则线程可以直接获取许可证资源并执行任务。如果许可证数量小于等于0,则线程会被阻塞,直到其他线程释放许可证资源,则当前线程才能重新获取许可证并执行任务。需要注意的是,一旦线程获取到许可证资源,则许可证数量就会减1。同理,每次释放许可证资源,许可证数量就会加1。

## 3、Semaphore的应用场景
Semaphore的应用场景较为广泛,主要用于控制并发数量,防止线程阻塞和死锁等问题。下面列举一些Semaphore的应用场景和示例代码:

### 场景1:限流器
Semaphore可用于实现限流器,即限制同时访问某个资源的线程数量。比如,我们可以使用Semaphore控制某个接口的并发数量,防止服务被过度访问而崩溃。下面是示例代码:

```
public class RateLimit {
  private Semaphore semaphore;

  public RateLimit(int permits) {
    this.semaphore = new Semaphore(permits);
  }

  public void acquire() {
    semaphore.acquire();
  }

  public void release() {
    semaphore.release();
  }
}
```

### 场景2:数据库连接池
Semaphore可用于实现数据库连接池,即限制同时连接数据库的线程数量。比如,我们可以使用Semaphore来限制连接数,防止数据库过度加载而崩溃。下面是示例代码:

```
public class DBConnectionPool {
  private final Semaphore semaphore;
  private final List<Connection> pool;

  public DBConnectionPool(int permits, List<Connection> pool) {
    this.semaphore = new Semaphore(permits, true);
    this.pool = pool;
  }

  public Connection acquire() throws InterruptedException {
    semaphore.acquire();
    return pool.remove(0);
  }

  public void release(Connection conn) {
    pool.add(conn);
    semaphore.release();
  }
}
```

### 场景3:线程池
Semaphore可用于实现线程池,即限制同时执行任务的线程数量。比如,我们可以使用Semaphore来控制线程池的大小,防止同时执行太多的任务而导致系统崩溃。下面是示例代码:

```
public class MyThreadPool {
  private final Semaphore semaphore;
  private final ExecutorService executor;

  public MyThreadPool(int permits, ExecutorService executor) {
    this.semaphore = new Semaphore(permits);
    this.executor = executor;
  }

  public void execute(Runnable task) throws InterruptedException {
    semaphore.acquire();
    executor.execute(() -> {
      try {
        task.run();
      } finally {
        semaphore.release();
      }
    });
  }
}
```

## 4、Semaphore的示例代码
下面给出一个基于Semaphore实现的生产者-消费者模型的示例代码,具体实现可以参考如下:

```
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.Semaphore;

class QueueBuffer<T> {
  Queue<T> buffer = new LinkedList<>();
  Semaphore producerSemaphore = new Semaphore(1);
  Semaphore consumerSemaphore = new Semaphore(0);
  int maxBufferSize = 10;

  public void put(T obj) throws InterruptedException {
    producerSemaphore.acquire();
    try {
      while (buffer.size() == maxBufferSize) {
        consumerSemaphore.release();
        producerSemaphore.acquire();
      }
      buffer.add(obj);
      System.out.println(Thread.currentThread().getName() + " put: " + obj);
      consumerSemaphore.release();
    } finally {
      producerSemaphore.release();
    }
  }

  public T get() throws InterruptedException {
    consumerSemaphore.acquire();
    try {
      while (buffer.isEmpty()) {
        producerSemaphore.release();
        consumerSemaphore.acquire();
      }
      T obj = buffer.poll();
      System.out.println(Thread.currentThread().getName() + " get: " + obj);
      producerSemaphore.release();
      return obj;
    } finally {
      consumerSemaphore.release();
    }
  }
}

public class ProducerConsumer {
  public static void main(String[] args) throws InterruptedException {
    QueueBuffer<Integer> buffer = new QueueBuffer<>();
    Thread producer1 = new Thread(() -> {
      try {
        for (int i = 1; i <= 10; i++) {
          buffer.put(i);
          Thread.sleep(1000);
        }
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }, "Producer1");

    Thread producer2 = new Thread(() -> {
      try {
        for (int i = 11; i <= 20; i++) {
          buffer.put(i);
          Thread.sleep(1000);
        }
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }, "Producer2");

    Thread consumer1 = new Thread(() -> {
      try {
        for (int i = 1; i <= 5; i++) {
          buffer.get();
          Thread.sleep(2000);
        }
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }, "Consumer1");

    Thread consumer2 = new Thread(() -> {
      try {
        for (int i = 6; i <= 10; i++) {
          buffer.get();
          Thread.sleep(2000);
        }
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }, "Consumer2");

    producer1.start();
    producer2.start();
    consumer1.start();
    consumer2.start();

    producer1.join();
    producer2.join();
    consumer1.join();
    consumer2.join();
  }
}
```

以上代码基于Semaphore实现了一个生产者-消费者模型,并且内置了两个生产者和两个消费者线程,其中生产者会生产1-20的数字,并将其放入缓冲区中,而消费者会从缓冲区中取出数据并进行处理(这里采用简单的输出操作)。而Semaphore则用于控制两个生产者之间的并发数量和两个消费者之间的并发数量,以确保线程安全性和程序的正确性。

## 结语
Semaphore是Java中一个非常实用的线程同步工具,可以帮助开发者控制并发访问数量、防止线程阻塞和死锁等问题,在多种场景下都有着广泛的应用。本文中介绍了Semaphore的简介、底层实现和应用场景,同时演示了Semaphore在生产消费模型中的实现方式,相信读者可以通过本文进一步熟悉Semaphore的使用方法,从而提高对Java并发编程的理解和实践能力。文章来源地址https://www.toymoban.com/news/detail-451099.html

到了这里,关于java并发-Semaphore的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java并发编程-volatile

    volatile 是 java 虚拟机提供的一种轻量级的同步机制,它有三个重要的特性: 保证可见性 不保证原子性 禁止指令重排 要理解这三个特性,就需要对 JMM (JAVA内存模型)有一定的了解才行。 主要解决的问题: JVM中,每个线程都会存在本地内存,本地内存是公共内存的副本,各

    2024年02月06日
    浏览(41)
  • Java并发编程实战

    2023年06月19日
    浏览(50)
  • Java-并发编程-进阶篇

    在上一篇幅中对并发编程进行了简单介绍:并发与并行,进程与线程,以及并发编程的简单代码 但是在企业中往往并不能解决实际问题,例如: 1.synchronized在企业开发中会大大降低系统的性能,有什么解决方式,或者其他的替代方案 2.当线程被创建并启动以后,它既不

    2024年02月06日
    浏览(63)
  • Java并发编程面试题

    目录 一、线程、进程、程序 二、线程状态  三、线程的七大参数 四、线程有什么优缺点? 五、start 和 run 方法有什么区别? 六、wait 和 sleep的区别? 七、lock与synchronized的区别 八、Volatile是线程安全的吗?底层原理是什么? 九、synchronized作用和底层原理? 十一、Thre

    2024年02月12日
    浏览(58)
  • 【并发编程】深入理解Java并发之synchronized实现原理

    分析: 通过 new MyThread() 创建了一个对象 myThread ,这时候堆中就存在了共享资源 myThread ,然后对 myThread 对象创建两个线程,那么thread1线程和thread2线程就会共享 myThread 。 thread1.start() 和 thead2.start() 开启了两个线程,CPU会随机调度这两个线程。假如 thread1 先获得 synchronized 锁,

    2024年02月04日
    浏览(59)
  • Java并发编程详解:实现高效并发应用的关键技术

    在当前的计算机领域,高效的并发编程对于Java开发人员而言变得越发重要。作为流行的编程语言,Java提供了强大的并发编程支持,使开发人员能够充分发挥多核处理器和线程的潜力,构建高性能、高吞吐量的应用程序。本文将深入探讨Java并发编程的关键技术,包括线程安全

    2024年02月13日
    浏览(50)
  • 【面试】java并发编程面试题

    java并发面试题 https://javaguide.cn/home.html java基础面试题 https://blog.csdn.net/jackfrued/article/details/44921941 java集合面试题 https://javaguide.cn/java/collection/java-collection-questions-01.html javaIO面试题 https://javaguide.cn/java/io/io-basis.html JVM面试题 https://javaguide.cn/java/jvm/jvm-garbage-collection.html 计算机网络

    2024年01月21日
    浏览(47)
  • 01.java并发编程面试宝典

    谈谈什么是线程池 线程池和数据库连接池非常类似,可以统一管理和维护线程,减少没有必要的开销。 因为频繁的开启线程或者停止线程,线程需要从新被 cpu 从就绪到运行状态调度,需要发生上下文切换 实际开发项目中 禁止自己 new 线程。必须使用线程池来维护和创建线

    2024年02月03日
    浏览(104)
  • java并发编程:ArrayBlockingQueue详解

    ArrayBlockingQueue 顾名思义:基于数组的阻塞队列。数组是要指定长度的,所以使用 ArrayBlockingQueue 时必须指定长度,也就是它是一个有界队列。它实现了 BlockingQueue 接口,有着队列、集合以及阻塞队列的所有方法。 ArrayBlockingQueue 是线程安全的,内部使用 ReentrantLock 来保证。A

    2024年02月08日
    浏览(59)
  • java并发编程:LinkedBlockingQueue详解

    在集合框架里,想必大家都用过ArrayList和LinkedList,也经常在面试中问到他们之间的区别。ArrayList和ArrayBlockingQueue一样,内部基于数组来存放元素,而LinkedBlockingQueue则和LinkedList一样,内部基于链表来存放元素。 LinkedBlockingQueue实现了BlockingQueue接口,这里放一张类的继承关系图

    2024年02月08日
    浏览(62)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包