java并发包里面的一个工具类Semaphore

Semaphore是java并发包里面的一个工具类,我们限制可以访问某些资源的线程数目就可以使用Semaphore了。这篇文章将对Semaphore的概念和使用进行一个详解。

在JAVA里面,我的理解是信号计数的作用,比如我想设置只能允许500个线程访问WebServer,那么如何控制500个数量哪?每来一个请求,就通过acquire()获取一个许可,然后数量自动减一,处理完成之后通过release()释放一个许可,数量自动加一。这样就实现了控制的作用,当然这个功能咱们自己通过锁的机制可以自己完成,不过使用Semaphore比较简单、方便,这也是它产生的原因。好了废话少说,写一段代码看看。

Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package com.taobao;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
/**
* Semaphore 测试代码
*
*/
public class Test implements Runnable {
// 只能5个线程同时访问
Semaphore semp = new Semaphore(5);
int num = 0;

@Override
public void run() {
// TODO Auto-generated method stub
try {
// 获取许可
semp.acquire();
System.out.println("这是第几个线程:" + this.num++);
//System.out.println(this.num);
Thread.sleep((long) (Math.random() * 10000));
// 访问完后,释放
semp.release();
System.out.println("空闲线程的数量:" + semp.availablePermits());
} catch (InterruptedException e) {
e.printStackTrace();
}

}

public static void main(String[] args) {
// 线程池
ExecutorService exec = Executors.newCachedThreadPool();
Test test = new Test();
// 模拟20个客户端访问
for (int index = 0; index < 10; index++) {
System.out.println("开启了第几个线程:"+index);
exec.execute(test);
}
// 退出线程池
exec.shutdown();

}
}

执行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
开启了第几个线程:0
开启了第几个线程:1
这是第几个线程:0
开启了第几个线程:2
这是第几个线程:1
开启了第几个线程:3
这是第几个线程:2
开启了第几个线程:4
这是第几个线程:3
开启了第几个线程:5
这是第几个线程:4
开启了第几个线程:6
开启了第几个线程:7
开启了第几个线程:8
开启了第几个线程:9
空闲线程的数量:1
这是第几个线程:5
空闲线程的数量:1
这是第几个线程:6
空闲线程的数量:1
这是第几个线程:7
空闲线程的数量:1
这是第几个线程:8
空闲线程的数量:1
这是第几个线程:9
空闲线程的数量:1
空闲线程的数量:2
空闲线程的数量:3
空闲线程的数量:4
空闲线程的数量:5

解释一下上面用到的几个函数:

availablePermits(): 返回空闲线程的数量

acquire(): 申请线程

release(): 释放线程

Executors.newCachedThreadPool(): 创建一个线程池,这个与本文没有什么关系

了解他的一些方法:

1、acquire(int permits)

从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞,或者线程已被中断。就好比是一个学生占两个窗口。这同时也对应了相应的release方法。

2、release(int permits)

释放给定数目的许可,将其返回到信号量。这个是对应于上面的方法,一个学生占几个窗口完事之后还要释放多少

3、availablePermits()

返回此信号量中当前可用的许可数。也就是返回当前还有多少个窗口可用。

4、reducePermits(int reduction)

根据指定的缩减量减小可用许可的数目。

5、hasQueuedThreads()

查询是否有线程正在等待获取资源。

6、getQueueLength()

返回正在等待获取的线程的估计数目。该值仅是估计的数字。

7、tryAcquire(int permits, long timeout, TimeUnit unit)

如果在给定的等待时间内此信号量有可用的所有许可,并且当前线程未被中断,则从此信号量获取给定数目的许可。

8、acquireUninterruptibly(int permits)

从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞。

基本上常见的使用方法都在这,Semaphore底层是由AQS和Uasafe完成的,篇幅问题在这里不赘述了。感谢各位支持。