当前位置: 首页 > article >正文

Java面试篇基础部分-Semaphore及其用法详解

  Semaphore 是一种基于计数的信号量,在定义信号量对象的时候可以设置一个阈值,然后基于这个阈值,多线程可以竞争访问信号量,线程竞争到许可的信号之后,开始执行具体的业务逻辑,业务逻辑在执行完成之后释放这个许可信号。

在这里插入图片描述
  如果许可信号竞争队列超过阈值,新加入的申请信号许可的线程就会被阻塞,知道有其他许可信号被释放。使用Semaphore可以控制同时访问资源的线程个数,例如,实现一个文件允许的并发访问数。

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

public class SemaphoreTest {
    public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool();
      	//创建Semaphore信号量,初始化许可大小为3
        final  Semaphore sp = new Semaphore(3);
        for(int i=0;i<10;i++){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e2) {
                e2.printStackTrace();
            }
          
            Runnable runnable = new Runnable(){
                    public void run(){
                    try {
                      	//请求获得许可,如果有可获得的许可则继续往下执行,
                       //许可数减1。否则进入阻塞状态
                        sp.acquire();
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                    System.out.println("线程" + Thread.currentThread().getName() + 
                            "进入,当前已有" + (3-sp.availablePermits()) + "个并发");
                    try {
                        Thread.sleep((long)(Math.random()*10000));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("线程" + Thread.currentThread().getName() + 
                            "即将离开");                    
                    sp.release();//释放许可,许可数加1
                    //下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元
                    System.out.println("线程" + Thread.currentThread().getName() + 
                            "已离开,当前已有" + (3-sp.availablePermits()) + "个并发");                    
                }
            };
            service.execute(runnable);            
        }
    }

}

  Semaphore 对于锁的申请与释放和ReentrantLock是类似的,通过acquire()方法和release()方法来获取和释放许可信号资源。

  Semaphore.acquire()方法与
ReentrantLock.lockInterruptibly()方法的效果是一样的,为可响应中断的锁。也就是说在等待获取许可信号的过程中可以被Thread.interrupt()方法中断而取消对许可信号的申请操作。

  除此之外,Semaphore也实现了可轮询的锁请求、定时锁的等功能,以及公平与非公平锁的定义在构造函数中设定

  Semaphore锁的释放操作也需要手动进行释放,为此为了避免线程因为异常没有正常释放锁,释放锁的操作必须在finally代码块中完成。

  Semaphore也可以用于实现一些对象池、资源池的构建,例如静态全局对象池、数据库连接池等等。

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

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockTest {
    public static void main(String[] args) {
        final Business business = new Business();
        ExecutorService executor =  Executors.newFixedThreadPool(3);
        for(int i=0;i<3;i++)
        {
            executor.execute(
                    new Runnable()
                    {
                        public void run()
                        {
                            business.service();
                        }
                    }
            
            );
        }
        executor.shutdown();
    }
    
    private static class Business
    {
        private int count;
        Lock lock = new ReentrantLock();
        Semaphore sp = new Semaphore(1);
        public void service() 
        {
            //lock.lock();
            try {
			    //当前线程使用count变量的时候将其锁住,不允许其他线程访问
                sp.acquire(); 
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            try {
                count++;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(count);
            } catch (RuntimeException e) {
                e.printStackTrace();
            }
            finally
            {
                //lock.unlock();
                sp.release();  //释放锁
            }
        }
    }        
    
}

http://www.kler.cn/news/321852.html

相关文章:

  • 数据结构-线性表的单链式存储结构图解及C语言实现
  • 都说网络安全缺口那么大,但为何招聘数量却不多?总算明白了!
  • Linux系统部署Mysql8.x修改密码并且设置远程连接
  • UniApp基于xe-upload实现文件上传组件
  • electron的常用弹窗简单案例
  • 15年408-数据结构
  • 老人跌倒扶不扶?涪城三职工给出响亮答案
  • 【docker】在IDEA工具内,远程操作服务器上的docker
  • Rust Web开发常用库
  • Leetcode 706. 设计哈希映射
  • 大屏可视化px转rem方案实现
  • webservice cxf框架 jaxrs jaxws spring整合 接口测试方法 wsdl报文详解 springboot整合 拦截器 复杂参数类型
  • 作者分享|eDNA研究梯级水坝对浮游植物和浮游动物群落变化的影响
  • WPF入门教学十九 属性动画与时间线
  • 计算机网络nat 映射案列
  • 基于nodejs+vue的校园二手物品交易系统
  • Vue3+Vite中引用Swiper11自动轮播、左右切换不生效,已解决
  • Android常用C++特性之std::equal
  • 【python append函数的一些细节】
  • 音频转MP3格式困难?如何轻松实现wav转mp3?
  • Vue3中el-table组件实现分页,多选以及回显
  • 基于 STM32 的高精度 PID 温控系统设计与实现:采用 Pt1000 温度传感器与 PWM 控制技术
  • HT5169内置BOOST升压的11W I2S输入D类音频功放
  • 【游戏设计】游戏中需要管理的数据分类
  • MYSQL-查看表中字段属性语法(三)
  • 找质数的方式
  • MATLAB中的无线通信系统测试和验证方法有哪些
  • 代码随想录Day17 图论-1
  • 调和级数枚举+前缀和,CF 731F - Video Cards
  • flutter 设置字体大小,适应各种屏幕