java高并发程序设计总结四:JDK并发包之信号量Semaphore

来源:互联网 发布:server2012网络连接 编辑:程序博客网 时间:2024/05/21 06:48

概念

信号量是对锁的一种扩展。不管是对于synchronized还是对于ReentrantLock锁来说,一次都只允许一个线程获取锁资源,其余的线程都只能处于等待状态。而信号量可以指定多个线程同时访问某一个资源,包括锁资源
Semaphore主要提供了一下两个构造函数
public Semaphore(int permits);初始化信号量并指定能同时访问的线程数量public Semaphore(int permits, boolean fair);在实现上面的要求时额外指定是否使用公平锁
“公平信号量”和”非公平信号量”的释放信号量的机制是一样的!不同的是它们获取信号量的机制:线程在尝试获取信号量许可时,对于公平信号量而言,如果当前线程不在CLH队列的头部,则排队等候;而对于非公平信号量而言,无论当前线程是不是在CLH队列的头部,它都会直接获取信号量。(CLH是其内部维护的一个等待队列)


主要方法

构造信号量对象时,必须指定信号量的准入数,即同时能申请多少个许可。(synchronized和ReentrantLock就只能申请一个许可)信号量的主要逻辑方法有:
public void acquire() throws InterruptedException尝试获得一个准入的许可,如果无法获得,线程就会一直等待,直接获得了一个许可或者当前线程被中断,后者会抛出中断异常public void acquireUnInterruptibly();与acquire作用相同,区别在于不响应中断public boolean tryAcquire();尝试去申请一个许可,如果能获得,则返回true,并获得许可,否则立马返回false,不会等待public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException;尝试在指定时间内获取一个许可,如果能获得,则返回true,并获得许可,否则等待timeout时间后还是没有获得,就返回false;在timeout时间内如果被中断,则会抛出中断异常public void release();用于在线程访问资源结束之后释放一个许可


信号量的使用代码

public class Main{    public static void main(String[] args){        //信号量测试        //创建能容纳20个线程的线程池        ExecutorService exec = Executors.newFixedThreadPool(20);        semthread sem = new semthread();        for(int i=0; i<20; i++)            exec.submit(sem);    }    //使用信号量设置五个线程同时进入,并设置成公平锁    public static Semaphore sema = new Semaphore(5,true);    public static class semthread extends Thread{        public void run(){            try{                sema.acquire();                Thread.sleep(2000);                System.out.println("hello "+Thread.currentThread().getId());                sema.release();            }            catch(Exception e){                e.printStackTrace();                System.out.println("semaphore exception...");            }        }    }}//代码运行结果:将会在两秒的时间间隔内以五个一组的形式输出而且在20的线程执行完毕之后,发现程序还没有结束,这是因为我们在这里使用的是线程池,线程池中的线程在执行完毕之后不会被销毁,而是重回线程池,等待被使用,期间一直处于等待状态,所以程序不会被结束


参考文献

java高并发程序设计第三章–Semaphore信号量
Semaphore信号量的底层实现和原理
阅读全文
0 0