java 并发编程工具类之 Semaphore

Semaphore也叫信号量,在JDK1.5被引入,可以用来控制同时访问特定资源的线程数量,通过协调各个线程,以保证合理的使用资源。
Semaphore内部维护了一组虚拟的许可,许可的数量可以通过构造函数的参数指定。

  • 访问特定资源前,必须使用acquire方法获得许可,如果许可数量为0,该线程则一直阻塞,直到有可用许可。
  • 访问资源后,使用release释放许可。

Semaphore和ReentrantLock类似,获取许可有公平策略和非公平许可策略,默认情况下使用非公平策略。
应用场景
Semaphore可以用来做流量分流,特别是对公共资源有限的场景,比如数据库连接。
假设有这个的需求,读取几万个文件的数据到数据库中,由于文件读取是IO密集型任务,可以启动几十个线程并发读取,但是数据库连接数只有10个,这时就必须控制最多只有10个线程能够拿到数据库连接进行操作。这个时候,就可以使用Semaphore做流量控制。

package com.learn.juc.semaphore;

import java.util.Date;
import java.util.concurrent.Semaphore;


public class SemaphoreTest {

    private static int conut = 40;


    public static void main(String[] args) throws InterruptedException {

        Semaphore semaphore = new Semaphore(2);


        for (int i = 0; i < 10; i++) {

            new Thread(new MyTest(semaphore)).start();
        }


    }
}

class MyTest implements Runnable {


    private Semaphore semaphore;

    public MyTest(Semaphore semaphore) {
       this.semaphore = semaphore;
    }

    @Override
    public void run() {

        try {
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName() + "====" + System.currentTimeMillis());
            Thread.sleep(1000);
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {

        }


    }
}

 

Semaphore实现主要基于java同步器AQS,不熟悉的可以移步这里 深入浅出java同步器。
内部使用state表示许可数量。

非公平策略

  1. acquire实现,核心代码如下:
final int nonfairTryAcquireShared(int acquires) {
    for (;;) {
        int available = getState();
        int remaining = available - acquires;
        if (remaining < 0 ||
            compareAndSetState(available, remaining))
            return remaining;
    }
}

acquires值默认为1,表示尝试获取1个许可,remaining代表剩余的许可数。

  • 如果remaining < 0,表示目前没有剩余的许可。
  • 当前线程进入AQS中的doAcquireSharedInterruptibly方法等待可用许可并挂起,直到被唤醒。

 release实现,核心代码如下:

protected final boolean tryReleaseShared(int releases) {
    for (;;) {
        int current = getState();
        int next = current + releases;
        if (next < current) // overflow
            throw new Error("Maximum permit count exceeded");
        if (compareAndSetState(current, next))
            return true;
    }
}

 

releases值默认为1,表示尝试释放1个许可,next 代表如果许可释放成功,可用许可的数量。

  • 通过unsafe.compareAndSwapInt修改state的值,确保同一时刻只有一个线程可以释放成功。
  • 许可释放成功,当前线程进入到AQS的doReleaseShared方法,唤醒队列中等待许可的线程。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值