允许多个线程同时访问:信号量semaphore
信号量为多线程协作提供了更为强大的控制方法。无论是内部锁synchronized
还是重入锁ReentranctLock
,一次只允许一个线程访问资源,而信号量可以指定多个线程同时访问某一个资源。
信号量的构造函数:
public Semaphore(int permits) {
this.sync = new Semaphore.NonfairSync(var1);
}
public Semaphore(int permits, boolean fair) {
this.sync = (Semaphore.Sync)(var2 ? new Semaphore.FairSync(var1) : new Semaphore.NonfairSync(var1));
}
permiits
参数指定信号量的准入数,也就是同时能申请多少个许可。当一个线程只允许申请一次时,相当于指定多少个线程可以访问某一个资源。fair
参数指定是否公平。
信号量主要逻辑方法:
public void acquire() throws InterruptedException
public void acquireUninterruptibly()
public boolean tryAcquire()
public boolean tryAcquire(long time, TimeUnit unit) throws InterruptedException
public void release()
-
acquire()
方法尝试获得一个准入许可,若无法获得,则线程等待,直到其他线程释放一个许可或当前线程中断。 -
acquireUninterruptibly()
方法和acquire()
类似,但是它不响应中断。 -
tryAcquire()
方法尝试获得一个许可,若成功则返回true
,失败则返回false
,不等待。 -
tryAcquire(long time, TimeUnit unit)
方法和tryAcquire()
类似,但它会等待时间time
。 -
release()
方法在线程访问资源结束后,释放一个许可。
Semaphore示例
package semaphore;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
/**
* @Time : 2019/05/06 下午 02:47
* @Author : xiuc_shi
**/
public class SemaphoreDemo implements Runnable {
final Semaphore semaphore = new Semaphore(5);
@Override
public void run() {
try {
semaphore.acquire();
Thread.sleep(2000);
System.out.println(Thread.currentThread().getId() + " Done");
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
semaphore.release();
}
}
public static void main(String[] args) {
ExecutorService es = Executors.newFixedThreadPool(20);
final SemaphoreDemo demo = new SemaphoreDemo();
for(int i = 0;i < 20;i++){
es.execute(demo);
}
es.shutdown();
}
}
信号量用完必须释放,和释放锁一样,否则可用的信号量会越来越少。
应用场景
Semaphore可以用于做流量控制,特别是公用资源有限的应用场景,比如数据库连接。假如有一个需求,要读取几万个文件的数据,因为都是IO密集型任务,我们可以启动几十个线程并发地读取,但是如果读到内存后,还需要存储到数据库中,而数据库的连接数只有10个,这时我们必须控制只有10个线程同时获取数据库连接保存数据,否则会报错无法获取数据库连接。这个时候,就可以使用Semaphore来做流量控制。(摘自《java并发编程的艺术》)
网友评论