Java并发编程之Semaphore使用指南

Semaphore能做什么事情

Semaphore(信号量)是用来控制同时访问特定资源的线程数量,通过协调各个线程以保证合理地使用公共资源。Semaphore可以用作流量控制,特别是公共资源有限的应用场景,比如数据库的连接。

Semaphore如何使用

Semaphore主要用于管理信号量,同样在创建Semaphore对象实例的时候通过传入构造参数设定可供管理的信号量的数值。简单说,信号量管理的信号就好比令牌,构造时传入令牌数量,也就是Semaphore控制并发的数量。线程在执行并发的代码前要先获取信号(通过aquire函数获取信号许可),执行后归还信号(通过release方法归还),每次acquire信号成功后,Semaphore可用的信号量就会减一,同样release成功之后,Semaphore可用信号量的数目会加一,如果信号量的数量减为0,acquire调用就会阻塞,直到release调用释放信号后,aquire才会获得信号返回。

一个例子:一个应用程序要读取几万个文件的数据,由于都是IO密集型任务,所以可以启动几十个(例如10)个线程并发地读取。读取到内存中后还要将数据存储到数据库,但是数据库的连接只有3个。此时就必须设置策略控制只有10个线程同时获取数据库连接并保存数据,否则会报错,无法连接到数据库,这时Semaphore就派上用场了,用它来做流量控制,即连接到数据库的线程数。

本例中有限的公共资源是数据库连接。Java实现如下:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class SemaphoreTest {

    /* 读取文件数据的线程数量,并创建此容量的线程池 */
    private static final int THREAD_COUNT = 10;
    private static ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT);

    /* 创建Semaphore对象实例,构造函数的参数指定信号量的数目,为了方便说明问题,设为3 */
    private static Semaphore semaphore = new Semaphore(3);

    public static void main(String[] args){

        /* 创建线程读取数据,并尝试获取数据库连接,将数据存储到数据库中 */
        for(int i = 0;i < THREAD_COUNT;i++){
            final int index = i;

            Runnable task = new Runnable() {
                public void run() {
                    try {
                        /*从远程读数据*/
                        System.out.println("thread-"+ index + " is reading data from remote host");

                        /* 通过acquire 函数获取数据库连接,如果成功将数据存储到数据库 */
                        semaphore.acquire();
                        System.out.println("thread-"+ index + " is saving data....");
                        /*模拟存储数据耗时*/
                        Thread.sleep(10);
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }finally {

                        /* 最终使用release 函数释放信号量 */
                        semaphore.release();
                    }
                }
            };
            executorService.execute(task);
        }
    }

}


复制代码

以上代码的执行结果如下图:

从执行结果不难发现,线程将数据读到内存后,先只能有三个线程先获取到数据库连接,完成数据存储后释放了信号量后,其他的线程才能获取数据库连接。

如果Semaphore管理的信号量只有一个,那么就退化为互斥锁了,如果多于一个信号量,就主要用来控制并发数。与通过控制线程数来控制并发数的方式相比,Semaphore能做到更加细粒度,只需要将被控制最大并发的代码放到acquire和release之间即可。

Java并发编程之CyclicBarrier使用指南

java并发之CountDownLatch使用指南

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值