zoukankan      html  css  js  c++  java
  • 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

    金麟岂能忍一世平凡 飞上了青天 天下还依然
  • 相关阅读:
    mysql主从复制+读写分离
    lnmp平台菜鸟入门级笔记
    Shell编程
    Shell编程之--“grep-awk-sed” 基础用法汇总
    Nginx
    LB负载均衡之Nginx-Proxy
    LB(Load balance)负载均衡集群-LVS
    HA(High available)-Keepalived高可用性集群(双机热备)单点实验
    HA(High available)--Heartbeat高可用性集群(双机热备)
    linux -小记(3) 问题:linux 安装epel扩展源报错
  • 原文地址:https://www.cnblogs.com/Auge/p/11767453.html
Copyright © 2011-2022 走看看