Semaphore: 信号量

Semaphore: 信号量

Semaphore: 可以指定多个线程同时访问某一资源。

一)、构造方法

//int permits:线程的准入数,即一个资源同时可以允许多少个线程访问
Semaphore semaphore = new Semaphore(int permits);
//boolean fair,指明锁的规则, false: 非公平锁, true: 公平锁
Semaphore semaphore = new Semaphore(int permits, boolean fair)

公平锁: 锁的顺序与线程的执行顺序有关

非公平锁:锁的执行顺序与线程的执行顺序无关

默认使用非公平锁

二)、获取许可的方法

1)、acquire():获取一个许可,如果获取失败,则线程等待,等待期间可以响应中 断。

 public void acquire() throws InterruptedException {
        //1.获取共享可中断的
        sync.acquireSharedInterruptibly(1);
    }


    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        //2.优先判断线程的中断状态
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            //3.获取许可处理
            doAcquireSharedInterruptibly(arg);
    }

2)、acquireUninterruptibly(): 获取许可,如果获取失败,则线程等待,在等待期 间不响应中断。

public void acquireUninterruptibly() {
    //1.获取一次许可
        sync.acquireShared(1);
    }

  public final void acquireShared(int arg) {
        if (tryAcquireShared(arg) < 0)
            //2.获取许可处理
            doAcquireShared(arg);
    }

3)、tryAcquire(): 尝试获取许可,若成功立即返回true,失败立即返回false。

   protected boolean tryAcquire(int arg) {
        throw new UnsupportedOperationException();
    }

4)、tryAcquire(long time, TimeUnit unit):

在指定时间内尝试获取许可,若获取失败返回false,成功返回true,在指定的时间内可以响应中断。

   public boolean tryAcquire(long timeout, TimeUnit unit)
        throws InterruptedException {
       //1.获取一次许可
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }

   public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
            throws InterruptedException {
       //2.判断线程的中断状态
        if (Thread.interrupted())
            throw new InterruptedException();
        return tryAcquireShared(arg) >= 0 ||
            //3.做获取许可的操作
            doAcquireSharedNanos(arg, nanosTimeout);
    }

三)、释放许可:

relase():开放一个线程访问资源,相当于关闭锁。

   public void release() {
       //释放一个共享
        sync.releaseShared(1);
    }

四)、信号量的使用举例

模拟食堂吃饭情景:

​ 食堂相当于一个共享资源,去食堂吃饭的人相当于一个访问食堂的线程,多个

​ 人同时进食堂吃饭,但食堂一次只能容纳5个人,如何控制食堂这个共享资源,

​ 语序5个线程同时访问。

使用Semaphore。

食堂访问线程:Canteen_SemahoreThread

一次只能允许5个线程访问

public class Canteen_SemaphoreThread implements Runnable{

    /**
     *   控制食堂的人流量,一次只允许5个人同时吃饭
     */
    private Semaphore semaphore ;

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

    @Override
    public void run() {
        //获取准入许可,相当于获取锁,若无法获取许可,线程则一直等待释放许可,等待过程中优先响应中断
        try {
            /**
             * 使用信号量来锁住一个资源,传入信号量时,指明允许资源同时访问的线程个数。
             */
            semaphore.acquire();
            System.out.println("我正在吃饭。。。");
            Thread.sleep(100);
            System.out.println("我吃完了、、、");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            //释放一个许可
            semaphore.release();
        }

    }
}

消费食堂线程: Canteen_SemaphoreTest

开启20个线程,一次只能有5个人在食堂吃饭。

/**
 * 测试信号量的使用,开启20个线程
 */
public class Canteen_SemaphoreTest {
    public static void main(String[] args) {
        //设置信号量的大小,一次食堂只能容纳5个人吃饭
        Semaphore semaphore = new Semaphore(5);
        ExecutorService executor = Executors.newFixedThreadPool(20);
        Canteen_SemaphoreThread canteenThread = new Canteen_SemaphoreThread(semaphore);
        for(int i = 0; i < 20; i++){
            executor.execute(canteenThread);
        }
    }
}

结果:

我正在吃饭。。。 pool-1-thread-1
我正在吃饭。。。 pool-1-thread-2
我正在吃饭。。。 pool-1-thread-3
我正在吃饭。。。 pool-1-thread-4
我正在吃饭。。。 pool-1-thread-5
我吃完了、、、 pool-1-thread-1
我正在吃饭。。。 pool-1-thread-6
我吃完了、、、 pool-1-thread-4
我吃完了、、、 pool-1-thread-5
我正在吃饭。。。 pool-1-thread-7
我正在吃饭。。。 pool-1-thread-8
我吃完了、、、 pool-1-thread-2
我吃完了、、、 pool-1-thread-3
我正在吃饭。。。 pool-1-thread-9
我正在吃饭。。。 pool-1-thread-10
我吃完了、、、 pool-1-thread-6
我正在吃饭。。。 pool-1-thread-11
我吃完了、、、 pool-1-thread-8
我吃完了、、、 pool-1-thread-7
我吃完了、、、 pool-1-thread-9
我吃完了、、、 pool-1-thread-10
我正在吃饭。。。 pool-1-thread-14
我正在吃饭。。。 pool-1-thread-13
我正在吃饭。。。 pool-1-thread-12
我正在吃饭。。。 pool-1-thread-15
我吃完了、、、 pool-1-thread-11
我正在吃饭。。。 pool-1-thread-16
我吃完了、、、 pool-1-thread-12
我吃完了、、、 pool-1-thread-15
我正在吃饭。。。 pool-1-thread-17
我正在吃饭。。。 pool-1-thread-18
我吃完了、、、 pool-1-thread-13
我正在吃饭。。。 pool-1-thread-19
我吃完了、、、 pool-1-thread-14
我正在吃饭。。。 pool-1-thread-20
我吃完了、、、 pool-1-thread-16
我吃完了、、、 pool-1-thread-19
我吃完了、、、 pool-1-thread-18
我吃完了、、、 pool-1-thread-20
我吃完了、、、 pool-1-thread-17

结果分析:

使用Semaphore semaphore = new Semaphore(5),指明共享资源允许同时访问的线程个数,开启20个食堂线程,有5个线程可以同时访问食堂,因此,刚开始打印了5个我正在吃饭,线程无等待。

代码gitHub地址:https://github.com/slob-cow/java_performance_optimization/tree/master/semaphore

猜你喜欢

转载自www.cnblogs.com/Auge/p/11767453.html