Semaphore(信号量)的使用

jdk1.5提供的api,位于java.util.concurrent.Semaphore
包下,常用方法有:

方法描述
void acquire()从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。 手机
void acquire(int permits)从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞,或者线程已被中断。
void acquireUninterruptibly()从此信号量中获取许可,在有可用的许可前将其阻塞。
void acquireUninterruptibly(int permits)从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞。
int availablePermits()返回此信号量中当前可用的许可数。
int drainPermits()获取并返回立即可用的所有许可。
protected Collection getQueuedThreads()返回一个 collection,包含可能等待获取的线程。
int getQueueLength()返回正在等待获取的线程的估计数目。
boolean hasQueuedThreads()查询是否有线程正在等待获取。
boolean isFair()如果此信号量的公平设置为 true,则返回 true。
protected void reducePermits(int reduction)根据指定的缩减量减小可用许可的数目。
void release()释放一个许可,将其返回给信号量。
void release(int permits)释放给定数目的许可,将其返回到信号量。
String toString()返回标识此信号量的字符串,以及信号量的状态。
boolean tryAcquire()仅在调用时此信号量存在一个可用许可,才从信号量获取许可。
boolean tryAcquire(int permits)仅在调用时此信号量中有给定数目的许可时,才从此信号量中获取这些许可。
boolean tryAcquire(int permits, long timeout, TimeUnit unit)如果在给定的等待时间内此信号量有可用的所有许可,并且当前线程未被中断,则从此信号量获取给定数目的许可。
boolean tryAcquire(long timeout, TimeUnit unit)如果在给定的等待时间内,此信号量有可用的许可并且当前线程未被中断,则从此信号量获取一个许可。

2个构造方法:
Semaphore(int permits)
创建具有给定的许可数和非公平的公平设置的 Semaphore。

Semaphore(int permits, boolean fair)
创建具有给定的许可数和给定的公平设置的 Semaphore,fair为true,则排在最前面的线程优先获取许可.

Semaphore
可以维护当前访问自身的线程个数,并提供了同步机制.使用Semaphore可以控制同时访问资源的线程个数.例如,实现一个文件允许的并发访问数.
Semaphore的实现的功能有点类似于厕所的坑可以同时提供给多少人使用,假设厕所有5个坑,有10个人要上厕所,那么同时只能有5个人能够使用,当5个人中的任何一个人离开厕所后,其他5个在等待的人就有一个人可以去使用了.如果在构建Semaphore的时候没有指定fair=true,那么这5个等待的人获取坑的机会是随机的.

单个信号量的Semaphore对象可以实现互斥的功能,并且可以是由一个线程获取了"锁",再由另一个线程释放"锁",这可应用于死锁恢复的一些场合.

从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个 release() 添加一个许可,从而可能释放一个正在阻塞的获取者,Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。

它与synchronized和Lock有点不同:
1.synchronized和Lock维护的是多个线程同时访问同一个资源,"锁"对象只有一个,并且是公用的."锁"的获取和释放必须是同一个线程.
2.Semaphore维护的是多个线程同时访问多个资源,"锁"的获取和释放必须可以是不同线程.

package com.example;

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

/**
 * Created by mChenys on 2016/5/15.
 */
public class SemaphoreTest {
    public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool();//创建一个带缓冲的线程池
        final Semaphore sp = new Semaphore(3);//创建3个信号量,即同一时刻最多只有3个线程可以访问资源
        for (int i = 0; i < 10; i++) {
            Runnable runnable = new Runnable() {
                public void run() {
                    try {
                        //获得信号量
                        sp.acquire();
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                    System.out.println("线程" + Thread.currentThread().getName() +
                            "进入,当前已有" + (3 - sp.availablePermits()) + "个并发");
                    try {
                        Thread.sleep((long) (Math.random() * 1000));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("线程" + Thread.currentThread().getName() + "即将离开");
                    //释放信号量,让后面在等待的线程可以继续acquire获取信号量,来访问目标资源
                    sp.release();
                    //下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元
                    System.out.println("线程" + Thread.currentThread().getName() +
                            "已离开,当前已有" + (3 - sp.availablePermits()) + "个并发");
                }
            };
            //提交任务给线程池执行
            service.execute(runnable);
        }
    }
}

运行结果:

线程pool-1-thread-2进入,当前已有3个并发
线程pool-1-thread-1进入,当前已有3个并发
线程pool-1-thread-3进入,当前已有3个并发
线程pool-1-thread-3即将离开
线程pool-1-thread-3已离开,当前已有2个并发
线程pool-1-thread-4进入,当前已有3个并发
线程pool-1-thread-1即将离开
线程pool-1-thread-1已离开,当前已有2个并发
线程pool-1-thread-5进入,当前已有3个并发
线程pool-1-thread-4即将离开
线程pool-1-thread-4已离开,当前已有2个并发
线程pool-1-thread-6进入,当前已有3个并发
线程pool-1-thread-2即将离开
线程pool-1-thread-2已离开,当前已有2个并发
线程pool-1-thread-7进入,当前已有3个并发
线程pool-1-thread-5即将离开
线程pool-1-thread-5已离开,当前已有2个并发
线程pool-1-thread-8进入,当前已有3个并发
线程pool-1-thread-6即将离开
线程pool-1-thread-6已离开,当前已有2个并发
线程pool-1-thread-10进入,当前已有3个并发
线程pool-1-thread-7即将离开
线程pool-1-thread-7已离开,当前已有2个并发
线程pool-1-thread-9进入,当前已有3个并发
线程pool-1-thread-8即将离开
线程pool-1-thread-8已离开,当前已有2个并发
线程pool-1-thread-9即将离开
线程pool-1-thread-9已离开,当前已有1个并发
线程pool-1-thread-10即将离开
线程pool-1-thread-10已离开,当前已有0个并发

由上面的运行结果可以看出,10个线程中同一时刻最多只有3个线程可以获取信号量,并发执行.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值