Java核心知识点学习----线程中的Semaphore学习,公共厕所排队策略
sem原理及基本操作
sem原理及基本操作Sem原理及基本操作概述在计算机科学中,Sem(Semaphore)是一种常用的同步机制,被广泛应用于多线程编程。
它通过控制对共享资源的访问,解决了多线程并发执行时可能出现的竞态条件和资源争用问题。
本文将介绍Sem的原理及基本操作,帮助读者更好地理解和应用Sem。
一、Sem原理Sem的原理基于信号量的概念,信号量是一种计数器,用于控制对共享资源的访问。
当多个线程同时访问一个共享资源时,信号量可以限制同时访问的线程数量,从而保证资源的正确使用。
Sem中的信号量可以被看作是一个整型变量,它具有两个基本操作:P操作(等待)和V操作(发信号)。
1. P操作(等待)P操作用于请求访问共享资源。
当一个线程想要访问共享资源时,它需要执行P操作,信号量的值将减1。
如果信号量的值小于0,表示当前没有可用资源,线程将被阻塞,直到有其他线程释放资源。
2. V操作(发信号)V操作用于释放共享资源。
当一个线程访问完共享资源后,需要执行V操作,信号量的值将加1。
如果有其他线程正在等待资源,则其中一个线程将被唤醒,可以继续执行。
通过P操作和V操作的协调,Sem实现了对共享资源的访问控制,避免了竞态条件和资源争用问题的发生。
二、Sem基本操作Sem的基本操作包括创建、初始化、P操作和V操作。
1. 创建使用Sem之前,需要先创建一个信号量对象。
创建信号量的方法通常是调用系统提供的API函数,传入相应的参数。
2. 初始化创建信号量后,需要对其进行初始化。
初始化的目的是设置信号量的初始值,即资源的可用数量。
初始化的方法通常是调用系统提供的API函数,传入初始值作为参数。
3. P操作当一个线程需要访问共享资源时,它执行P操作。
P操作的实现方式是通过原子操作,即保证P操作的执行是不可中断的。
当线程执行P操作时,如果信号量的值大于0,则将其减1并继续执行;如果信号量的值等于0,则线程被阻塞,直到有其他线程执行V操作。
4. V操作当一个线程访问完共享资源后,它执行V操作。
java高级知识点总结ppt
java高级知识点总结ppt一、泛型1. 为什么需要泛型- 早期的Java中,集合类中的元素都是Object类型,需要进行类型转换导致代码冗余和安全隐患- 泛型可以在编译时进行类型检查,提高代码的安全性和可读性2. 泛型的相关概念- 泛型类:class MyClass<T> {}- 泛型接口:interface MyInterface<T> {}- 泛型方法:public <T> void myMethod(T t) {}- 泛型通配符:List<?>、List<? extends Number>、List<? super Number>3. 泛型的继承和通配符- extends关键字用于指定类型上限- super关键字用于指定类型下限- PECS(Producer Extends, Consumer Super)原则4. 类型擦除- Java中的泛型是通过擦除实现的- 泛型在编译时会被擦除为Object类型- 泛型参数的实际类型信息会丢失5. 泛型使用的注意事项- 泛型数组的创建是不允许的- 泛型类型参数不能是基本类型- 无法创建参数化类型的数组二、注解1. 什么是注解- 注解是一种用于向编译器、开发工具和其他程序读取信息的标记- 可以用于标记方法、字段、类等2. 常用的注解- @Override:用于标记重写父类的方法- @Deprecated:用于标记已过时的方法或类- @SuppressWarnings:用于忽略编译器警告- @FunctionalInterface:用于标记函数式接口- @Target:用于指定注解的作用目标- @Retention:用于指定注解的生命周期- @Documented:用于指定注解是否包含在JavaDoc中3. 自定义注解- 定义注解:@interface MyAnnotation {}- 注解元素:可以是基本数据类型、枚举类型、Class类型,或者其他注解类型 - 使用注解:@MyAnnotation4. 注解处理器- 注解处理器是用来处理注解的工具- 可以在编译时、运行时或者在自定义工具中处理注解5. 元注解- 元注解用于标记其他注解的注解- 常用的元注解有:@Target、@Retention、@Inherited、@Documented三、反射1. 什么是反射- 反射是指程序在运行时能够获取自身的信息,并能够对自身进行操作的能力2. Class类- 反射的核心是Class类,代表了一个类的属性和方法- 通过Class类可以获取类的构造函数、字段、方法等信息- 可以通过Class类创建类的对象3. 反射的应用- 动态代理:通过反射实现动态生成代理类- 注解处理器:通过反射获取注解信息并进行相应处理- 类加载器:通过反射加载指定路径下的类文件4. 反射的性能问题- 反射在性能上有一定的损耗- 应尽量避免在性能敏感的代码中大量使用反射5. 相关类和接口- Field:代表类的字段- Method:代表类的方法- Constructor:代表类的构造函数- Modifier:提供了用于反射的访问修饰符常量四、Lambda表达式1. 什么是Lambda表达式- Lambda表达式是一种匿名函数,可以作为参数传递给其他方法- 包含三个部分:参数列表、箭头符号、方法体2. Lambda表达式的特点- 简洁:去除了冗余的语法- 方便:可以直接以函数式接口变量接收Lambda表达式3. 函数式接口- 函数式接口是指只包含一个抽象方法的接口- 可以使用@FunctionalInterface注解来标记一个接口为函数式接口 - Java中内置了一些常用的函数式接口,如Runnable、Comparator等4. Lambda表达式的应用- 可以使用Lambda表达式来简化匿名内部类的写法- 可以用于简化集合类的遍历、排序等操作- 可以用于简化线程的创建和启动5. Lambda表达式的限制- 只能用于函数式接口- 不能使用break和continue关键字- 不能改变非final的局部变量的值五、并发编程1. 线程安全性- 多线程程序的最大挑战之一是确保数据的一致性和正确性- synchronized关键字和Lock接口是保证线程安全性的常用手段2. 并发容器- Java中提供了一些线程安全的集合类,如ConcurrentHashMap、CopyOnWriteArrayList 等- 这些集合类在多线程环境下能够安全地进行并发访问3. 线程池- 线程池可以管理和复用线程,避免线程频繁创建和销毁的开销- Executors类提供了创建线程池的工厂方法- ThreadPoolExecutor类提供了更灵活的线程池配置4. 原子操作- 原子操作是指不可被中断的一个或一系列操作- Java中提供了一些原子操作的类,如AtomicInteger、AtomicLong等5. 并发工具类- Java提供了一些并发工具类,如CountDownLatch、Semaphore、CyclicBarrier等,用于解决特定的并发问题总结本次总结了Java中的一些高级知识点,包括泛型、注解、反射、Lambda表达式和并发编程。
java多线程-Semaphore信号量使用
java多线程-Semaphore信号量使⽤介绍 信号量(Semaphore),有时被称为信号灯,是在多线程环境下使⽤的⼀种设施, 它负责协调各个线程, 以保证它们能够正确、合理的使⽤公共资源。
概念 Semaphore分为单值和多值两种,前者只能被⼀个线程获得,后者可以被若⼲个线程获得。
Semaphore当前在多线程环境下被扩放使⽤,操作系统的信号量是个很重要的概念,在进程控制⽅⾯都有应⽤。
Java并发库Semaphore 可以很轻松完成信号量控制,Semaphore可以控制某个资源可被同时访问的个数,通过 acquire() 获取⼀个许可,如果没有就等待,⽽ release() 释放⼀个许可。
⽐如在Windows下可以设置共享⽂件的最⼤客户端访问个数。
单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由⼀个线程获得了“锁”,再由另⼀个线程释放“锁”,这可应⽤于死锁恢复的⼀些场合。
实例 现在有⼀个三个信号灯,启动10个线程分别获取信号灯,当信号灯被占⽤时,其他线程只能等待,当信号灯被释放则等待线程获取信号灯。
1public class SemaphoreTest {2public static void main(String[] args) {3 ExecutorService pool = Executors.newCachedThreadPool();4final Semaphore semaphore = new Semaphore(3,true);56for (int i = 0; i < 10; i++) {7 Runnable runnable = new Runnable() {8 @Override9public void run() {10try {11 semaphore.acquire();//获取信号灯许可12 } catch (InterruptedException e) {13// TODO Auto-generated catch block14 e.printStackTrace();15 }16 System.out.println("Thread "+Thread.currentThread().getName()+" 进⼊" +"当前系统的并发数是:"+(3-semaphore.availablePermits()));17try {18 Thread.sleep(new Random().nextInt(1000));19 } catch (InterruptedException e) {20// TODO Auto-generated catch block21 e.printStackTrace();22 }23 System.out.println("Thread "+Thread.currentThread().getName()+" 即将离开");24 semaphore.release();//释放信号灯25 System.out.println("Thread "+Thread.currentThread().getName()+" 已经离开,当前系统的并发数是:"+(3-semaphore.availablePermits()));26 }27 };28 pool.execute(runnable);2930 }31 }32 } 另外需要注意的⼀点是,信号灯可以由⼀个线程使⽤,然后由另⼀个线程来进⾏释放,⽽锁只能由同⼀个线程启动和释放,不然就好发⽣死锁,这⼀点需要格外注意。
java线程队列的用法
java线程队列的用法
Java线程队列是一种用于管理和调度多线程任务的数据结构。
在Java中,线程队列通常使用ConcurrentLinkedQueue、LinkedBlockingQueue或PriorityBlockingQueue等类来实现。
这些队列提供了线程安全的操作,可以用于在多线程环境下进行任务调度和管理。
首先,让我们来看一下ConcurrentLinkedQueue。
这是一个基于链接节点的无界线程安全队列,它采用了无锁的线程安全算法,适用于高并发的场景。
它提供了常见的队列操作方法,如add、offer、poll、peek等,可以用于在线程池中管理任务。
另外一个常用的线程队列是LinkedBlockingQueue,它是一个基于链表的有界队列。
它可以指定队列的容量,当队列满时会阻塞生产者线程,直到队列有空间为止。
这种队列适合于限制任务数量的场景,比如控制线程池的最大任务数。
除了上述两种队列外,还有PriorityBlockingQueue,它是一个支持优先级的无界阻塞队列。
在这种队列中,元素按照它们的自然顺序或者根据构造队列时提供的Comparator进行排序。
这种队列
适合于需要按照优先级处理任务的场景。
在实际应用中,我们可以利用这些线程队列来实现生产者-消费者模式、任务调度和消息传递等功能。
通过合理选择队列类型和合理设置队列容量,可以提高多线程程序的效率和性能。
总的来说,Java线程队列是多线程编程中非常重要的一部分,它提供了一种安全、高效的方式来管理和调度多线程任务。
合理地使用线程队列可以帮助我们编写出稳定、高性能的多线程程序。
Java信号量全解析
Java信号量全解析前⾔:Semaphore(信号量)是⼀个线程同步结构,⽤于在线程间传递信号,以避免出现信号丢失(译者注:下⽂会具体介绍),或者像锁⼀样⽤于保护⼀个关键区域。
⾃从5.0开始,jdk在java.util.concurrent包⾥提供了Semaphore 的官⽅实现,因此⼤家不需要⾃⼰去实现Semaphore。
但是还是很有必要去熟悉如何使⽤Semaphore及其背后的原理内容主题:⼀、简单的Semaphore实现下⾯是⼀个信号量的简单实现:public class Semaphore {private boolean signal = false;public synchronized void take() {this.signal = true;this.notify();1011}public synchronized void release() throws InterruptedException{while(!this.signal) wait();this.signal = false;}}Take⽅法发出⼀个被存放在Semaphore内部的信号,⽽Release⽅法则等待⼀个信号,当其接收到信号后,标记位signal被清空,然后该⽅法终⽌。
使⽤这个semaphore可以避免错失某些信号通知。
⽤take⽅法来代替notify,release⽅法来代替wait。
如果某线程在调⽤release等待之前调⽤take⽅法,那么调⽤release⽅法的线程仍然知道take⽅法已经被某个线程调⽤过了,因为该Semaphore 内部保存了take⽅法发出的信号。
⽽wait和notify⽅法就没有这样的功能。
当⽤semaphore来产⽣信号时,take和release这两个⽅法名看起来有点奇怪。
这两个名字来源于后⾯把semaphore当做锁的例⼦,后⾯会详细介绍这个例⼦,在该例⼦中,take和release这两个名字会变得很合理。
java semephone使用案列
Java Semaphone是一个用于线程控制的工具,它可以控制同时访问共享资源的线程数量。
使用Java Semaphone可以很好地保护共享资源,避免多个线程同时访问造成的数据不一致性问题。
下面将介绍几个Java Semaphone的使用案例。
一、生产者用户模型在生产者用户模型中,生产者线程负责生产产品,而用户线程则负责消费产品。
生产者和用户共享一个缓冲区,为了避免生产者在缓冲区已满时继续生产,或者用户在缓冲区为空时继续消费,需要使用Java Semaphone来控制缓冲区的访问。
具体实现如下:1. 创建一个Semaphore对象,用于控制缓冲区的访问权限。
2. 当生产者生产一个产品时,首先需要获取Semaphore的许可。
3. 如果缓冲区已满,则生产者需要等待,直到有用户消费了产品,释放了许可。
4. 当用户消费一个产品时,也需要获取Semaphore的许可。
5. 如果缓冲区为空,则用户需要等待,直到有生产者生产了新的产品,释放了许可。
通过使用Semaphore来控制缓冲区的访问,可以实现生产者和用户的有效协作,避免了资源竞争和数据不一致的问题。
二、连接池在连接池中,多个线程需要共享有限的资源,例如数据库连接。
为了避免过多的线程同时获取连接,导致连接池资源耗尽,需要使用Java Semaphone来控制连接的访问。
具体实现如下:1. 创建一个Semaphore对象,设置连接池的大小作为许可数量。
2. 当线程需要获取连接时,首先需要获取Semaphore的许可。
3. 如果连接池已满,则线程需要等待,直到有其他线程释放了连接,释放了许可。
4. 当线程使用完连接后,需要释放连接,并释放Semaphore的许可。
通过使用Semaphore来控制连接池的访问,可以避免连接池资源耗尽的问题,保证多个线程能够合理地共享连接资源。
三、并发限流在并发限流的场景中,需要控制系统能够同时处理的请求数量,避免系统被过多的请求压垮。
深入理解Semaphore
深入理解Semaphore使用Semaphore是计数信号量。
Semaphore管理一系列许可证。
每个acquire方法阻塞,直到有一个许可证可以获得然后拿走一个许可证;每个release方法增加一个许可证,这可能会释放一个阻塞的acquire方法。
然而,其实并没有实际的许可证这个对象,Semaphore只是维持了一个可获得许可证的数量。
Semaphore经常用于限制获取某种资源的线程数量。
下面举个例子,比如说操场上有5个跑道,一个跑道一次只能有一个学生在上面跑步,一旦所有跑道在使用,那么后面的学生就需要等待,直到有一个学生不跑了,下面是这个例子:/*** 操场,有5个跑道* Created by Xingfeng on 2016-12-09.*/public class Playground {/*** 跑道类*/static class Track {private int num;public Track(int num) {this.num = num;}@Overridepublic String toString() {return "Track{" +"num=" + num +'}';}}private Track[] tracks = {new Track(1), new Track(2), new Track(3), new Track(4), new Track(5)};private boolean[] used = new boolean[5];private Semaphore semaphore = new Semaphore(5, true);/*** 获取一个跑道*/public Track getTrack() throws InterruptedException {semaphore.acquire(1);return getNextAvailableTrack();}/*** 返回一个跑道** @param track*/public void releaseTrack(Track track) {if (makeAsUsed(track))semaphore.release(1);}/*** 遍历,找到一个没人用的跑道** @return*/private Track getNextAvailableTrack() {for (int i = 0; i < used.length; i++) {if (!used[i]) {used[i] = true;return tracks[i];}}return null;}/*** 返回一个跑道** @param track*/private boolean makeAsUsed(Track track) {for (int i = 0; i < used.length; i++) {if (tracks[i] == track) {if (used[i]) {used[i] = false;return true;} else {return false;}}}return false;}}从上面可以看到,创建了5个跑道对象,并使用一个boolean类型的数组记录每个跑道是否被使用了,初始化了5个许可证的Semaphore,在获取跑道时首先调用acquire(1)获取一个许可证,在归还一个跑道是调用release(1)释放一个许可证。
java semaphore用法
java semaphore用法Semaphore是Java中提供的一种用于控制并发访问的机制。
它在多线程编程中被广泛使用,可以帮助管理共享资源的访问,避免竞态条件的发生。
本文将详细介绍Semaphore的用法,包括创建和初始化Semaphore对象、获取和释放许可、以及如何在多线程环境下使用Semaphore来实现同步。
在开始之前,我们先来了解一下什么是信号量。
信号量是一种计数器,用来控制对共享资源的访问。
它主要包含两个操作:P操作(等待)和V操作(发送信号)。
P操作会将信号量的值减一,如果结果小于零,则进程阻塞等待;V操作会将信号量的值加一,如果结果不大于零,表示有进程正在等待,会唤醒其中的一个或多个进程。
在Java中,Semaphore类是对信号量的封装。
我们可以通过它来控制并发访问的线程数,从而实现对共享资源的控制。
接下来,我们将一步一步地介绍Semaphore的用法。
首先,我们需要创建Semaphore对象。
Semaphore的构造函数有两个重载形式,一种是只传入一个整数作为许可的数量,另一种是传入一个整数和一个布尔值,用来指定是否公平地获取许可。
下面是一个示例:Semaphore semaphore = new Semaphore(5); 创建一个许可数量为5的Semaphore对象在上面的代码中,我们创建了一个许可数量为5的Semaphore对象,这意味着最多可以同时有5个线程访问共享资源。
接下来,我们可以使用Semaphore对象的acquire()方法来获取许可。
该方法会使当前线程等待,直到获取到一个许可为止。
一旦获取到许可,Semaphore 的许可数量就会减一。
下面是一个示例:semaphore.acquire(); 获取一个许可在上面的代码中,我们调用了acquire()方法来获取一个许可。
如果此时许可数量为0,则当前线程会被阻塞,直到有其它线程释放许可。
当我们完成对共享资源的访问后,需要手动释放许可,以供其它线程使用。
Semaphore
Semaphore疯狂创客圈经典图书:⾯试必备 + ⾯试必备 + ⾯试必备【】疯狂创客圈经典图书:⼤⼚必备 + ⼤⼚必备 + ⼤⼚必备【】⼊⼤⼚+涨⼯资必备:⾼并发【亿级流量IM实战】实战系列【 SpringCloud Nginx秒杀】实战系列【】JUC ⾼并发⼯具类(3⽂章)与⾼并发容器类(N⽂章):1234561 Semaphore是什么?Semaphore是计数信号量。
Semaphore管理⼀系列许可。
每个acquire⽅法阻塞,直到有⼀个许可证可以获得然后拿⾛⼀个许可证;每个release⽅法增加⼀个许可,这可能会释放⼀个阻塞的acquire⽅法。
然⽽,其实并没有实际的许可这个对象,Semaphore只是维持了⼀个可获得许可证的数量。
⽐如:停车场⼊⼝⽴着的那个显⽰屏,每有⼀辆车进⼊停车场显⽰屏就会显⽰剩余车位减1,每有⼀辆车从停车场出去,显⽰屏上显⽰的剩余车辆就会加1,当显⽰屏上的剩余车位为0时,停车场⼊⼝的栏杆就不会再打开,车辆就⽆法进⼊停车场了,直到有⼀辆车从停车场出去为⽌。
⽐如:在学⽣时代都去餐厅打过饭,假如有3个窗⼝可以打饭,同⼀时刻也只能有3名同学打饭。
第四个⼈来了之后就必须在外⾯等着,只要有打饭的同学好了,就可以去相应的窗⼝了 。
2 怎么使⽤ Semaphore2.1 构造⽅法//创建具有给定的许可数和⾮公平的公平设置的 Semaphore。
Semaphore(int permits)//创建具有给定的许可数和给定的公平设置的 Semaphore。
Semaphore(int permits, boolean fair)2.2 重要⽅法在上⾯我们使⽤最基本的acquire⽅法和release⽅法就可以实现Semaphore最常见的功能,不过其他⽅法还是需要我们去了解⼀下的。
1、acquire(int permits)从此信号量获取给定数⽬的许可,在提供这些许可前⼀直将线程阻塞,或者线程已被中断。
java的semaphore用法
在Java编程中,Semaphore是一个非常有用的工具,它可以用来控制对共享资源的访问。
它是线程同步的一种方法,可以用于限制同时访问某个资源的线程数量。
在本文中,我将深入探讨Java中Semaphore的用法,理解其原理和实际应用。
1. Semaphore的概念Semaphore是一个计数信号量,用来控制对共享资源的访问。
它维护着一个许可的计数器,线程需要在使用资源前获取许可,使用完后释放许可。
当许可计数为0时,其他线程需要等待直到有许可可用。
2. Semaphore的基本用法在Java中,Semaphore可以通过acquire()获取许可,release()释放许可。
我们可以通过构造函数来指定初始的许可数量,也可以通过tryAcquire()来尝试获取许可但不阻塞线程。
3. Semaphore的高级用法除了基本的acquire()和release()方法外,Semaphore还提供了一些高级的用法,比如acquireUninterruptibly()在获取许可时不响应线程中断,tryAcquire(timeout)在指定时间内获取许可等。
4. Semaphore的实际应用Semaphore在实际应用中非常有用,比如在多线程环境下控制对数据库连接池的访问、限制网络资源的并发访问等。
它可以有效地避免资源的过度利用和性能下降。
5. 个人观点和总结我个人认为,Semaphore是Java多线程编程中一个非常重要的工具,它可以帮助我们管理共享资源的访问,避免竞争和死锁等问题。
掌握Semaphore的用法,可以让我们编写出更安全、高效的多线程程序。
Java中Semaphore的用法既有基本的acquire()和release(),又有高级的用法如acquireUninterruptibly()和tryAcquire(timeout),在实际应用中可以帮助我们解决多线程访问共享资源的问题。
掌握Semaphore的技巧,可以让我们写出更高质量、安全性更高的Java多线程程序。
Java中Semaphore(信号量)的使用
Java中Semaphore(信号量)的使⽤Java中Semaphore(信号量)的使⽤Semaphore 的作⽤:在 java 中,使⽤了 synchronized 关键字和 Lock 锁实现了资源的并发访问控制,在同⼀时间只允许唯⼀了线程进⼊临界区访问资源 (读锁除外),这样⼦控制的主要⽬的是为了解决多个线程并发同⼀资源造成的数据不⼀致的问题。
在另外⼀种场景下,⼀个资源有多个副本可供同时使⽤,⽐如打印机房有多个打印机、厕所有多个坑可供同时使⽤,这种情况下,Java 提供了另外的并发访问控制 -- 资源的多副本的并发访问控制,今天学习的信号量 Semaphore 即是其中的⼀种。
Semaphore 实现原理初探:Semaphore 是⽤来保护⼀个或者多个共享资源的访问,Semaphore 内部维护了⼀个计数器,其值为可以访问的共享资源的个数。
⼀个线程要访问共享资源,先获得信号量,如果信号量的计数器值⼤于 1,意味着有共享资源可以访问,则使其计数器值减去 1,再访问共享资源。
如果计数器值为 0, 线程进⼊休眠。
当某个线程使⽤完共享资源后,释放信号量,并将信号量内部的计数器加 1,之前进⼊休眠的线程将被唤醒并再次试图获得信号量。
就好⽐⼀个厕所管理员,站在门⼝,只有厕所有空位,就开门允许与空侧数量等量的⼈进⼊厕所。
多个⼈进⼊厕所后,相当于 N 个⼈来分配使⽤ N 个空位。
为避免多个⼈来同时竞争同⼀个侧卫,在内部仍然使⽤锁来控制资源的同步访问。
Semaphore 的使⽤:Semaphore 使⽤时需要先构建⼀个参数来指定共享资源的数量,Semaphore 构造完成后即是获取 Semaphore、共享资源使⽤完毕后释放 Semaphore。
Semaphore semaphore = new Semaphore(10,true);semaphore.acquire();//do something heresemaphore.release();下⾯的代码就是模拟控制商场厕所的并发使⽤:public class ResourceManage {private final Semaphore semaphore ;private boolean resourceArray[];private final ReentrantLock lock;public ResourceManage() {this.resourceArray = new boolean[10];//存放厕所状态this.semaphore = new Semaphore(10,true);//控制10个共享资源的使⽤,使⽤先进先出的公平模式进⾏共享;公平模式 this.lock = new ReentrantLock(true);//公平模式的锁,先来的先选for(int i=0 ;i<10; i++){resourceArray[i] = true;//初始化为资源可⽤的情况}}public void useResource(int userId){semaphore.acquire();try{//semaphore.acquire();int id = getResourceId();//占到⼀个坑System.out.print("userId:"+userId+"正在使⽤资源,资源id:"+id+"\n");Thread.sleep(100);//do something,相当于于使⽤资源resourceArray[id] = true;//退出这个坑}catch (InterruptedException e){e.printStackTrace();}finally {semaphore.release();//释放信号量,计数器加1}}private int getResourceId(){int id = -1;lock.lock();try {//lock.lock();//虽然使⽤了锁控制同步,但由于只是简单的⼀个数组遍历,效率还是很⾼的,所以基本不影响性能。
java程序员修炼之路线程篇十八:Semaphore
java程序员修炼之路线程篇十八:Semaphore
Java程序员修炼之路线程篇十八:Semaphore
Semaphore在java线程控制中通常被用作资源的限制访问数量,如果我们想让某个资源同时只能有一定数量的线程访问,那么我们就可以使用Semaphore来进行限制了。
Semaphore将限制数量概念化成一个维护一组许可证的对象,我们可以通过构造器Semaphore(int permits)来初始化一个Semaphore对象,其中permits指定了许可证的数量。
许可证还存在一个公平策略的问题,因为资源本身被限制访问,当有多个线程在等待访问许可证时,如果采用非公平策略则不保证获取许可证的顺序,如果采用公平策略则按照先来先得的顺序发放许可证。
默认情况下,采用的是非公平策略,如果想使用公平策略,需要使用构造器Semaphore(int permits,boolean fair),当我们把fair设置为true时,就采用了公平策略。
公平策略能防止线程被饿死,但是非公平策略的处理速度有优势。
Semaphore提供了一系列方法来完成资源的限制访问,详细的方法描述建议大家查看java doc文档,这里面给出几个最为常用的方法介绍:1.acquire方法获取一个许可证,如果没有可用的许可证则会阻塞。
2.availablePermits方法返回当前可用许可证的数量。
3.release 方法释放一个许可证,可用许可证的数量会加1.为了描述Semaphore 的应用,我们看一个例子:
例子中创建了三个线程来访问一个被限制的资源Number,例子清晰地描述了Semaphore的使用。
在下一篇文章中我将跟大家聊一聊Phaser的使用,请大家持续关注。
详解Java信号量Semaphore
详解Java信号量Semaphore Semaphore也是⼀个同步器,和前⾯两篇说的CountDownLatch和CyclicBarrier不同,这是递增的,初始化的时候可以指定⼀个值,但是不需要知道需要同步的线程个数,只需要在同步的地⽅调⽤acquire⽅法时指定需要同步的线程个数;⼀.简单使⽤ 同步两个⼦线程,只有其中两个⼦线程执⾏完毕,主线程才会执⾏:package com.example.demo.study;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;public class Study0217 {//创建⼀个信号量的实例,信号量初始值为0static Semaphore semaphore = new Semaphore(0);public static void main(String[] args) throws Exception {ExecutorService pool = Executors.newFixedThreadPool(3);pool.submit(()->{System.out.println("Thread1---start");//信号量加⼀semaphore.release();});pool.submit(()->{System.out.println("Thread2---start");//信号量加⼀semaphore.release();});pool.submit(()->{System.out.println("Thread3---start");//信号量加⼀semaphore.release();});//等待两个⼦线程执⾏完毕就放过,必须要信号量等于2才放过semaphore.acquire(2);System.out.println("两个⼦线程执⾏完毕");//关闭线程池,正在执⾏的任务继续执⾏pool.shutdown();}}这个信号量也可以复⽤,类似CyclicBarrier:package com.example.demo.study;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;public class Study0217 {//创建⼀个信号量的实例,信号量初始值为0static Semaphore semaphore = new Semaphore(0);public static void main(String[] args) throws Exception {ExecutorService pool = Executors.newFixedThreadPool(3);pool.submit(()->{System.out.println("Thread1---start");//信号量加⼀semaphore.release();});pool.submit(()->{System.out.println("Thread2---start");//信号量加⼀semaphore.release();});//等待两个⼦线程执⾏完毕就放过,必须要信号量等于2才放过semaphore.acquire(2);System.out.println("⼦线程1,2执⾏完毕");pool.submit(()->{System.out.println("Thread3---start");//信号量加⼀semaphore.release();});pool.submit(()->{System.out.println("Thread4---start");//信号量加⼀semaphore.release();});semaphore.acquire(2);System.out.println("⼦线程3,4执⾏完毕");//关闭线程池,正在执⾏的任务继续执⾏pool.shutdown();}}⼆.信号量原理 看看下⾯这个图,可以知道信号量Semaphore还是根据AQS实现的,内部有个Sync⼯具类操作AQS,还分为公平策略和⾮公平策略;构造器://默认是⾮公平策略public Semaphore(int permits) {sync = new NonfairSync(permits);}//可以根据第⼆个参数选择是公平策略还是⾮公平策略public Semaphore(int permits, boolean fair) {sync = fair ? new FairSync(permits) : new NonfairSync(permits);}acquire(int permits)⽅法:public void acquire(int permits) throws InterruptedException {if (permits < 0) throw new IllegalArgumentException();sync.acquireSharedInterruptibly(permits);}//AQS中的⽅法public final void acquireSharedInterruptibly(int arg)throws InterruptedException {if (Thread.interrupted()) throw new InterruptedException();//这⾥根据⼦类是公平策略还是⾮公平策略if (tryAcquireShared(arg) < 0)//获取失败会进⼊这⾥,将线程放⼊阻塞队列,然后再尝试,还是失败的话就调⽤park⽅法挂起当前线程doAcquireSharedInterruptibly(arg);}//⾮公平策略protected int tryAcquireShared(int acquires) {return nonfairTryAcquireShared(acquires);}final int nonfairTryAcquireShared(int acquires) {//⼀个⽆限循环,获取state剩余的信号量,因为每调⽤⼀次release()⽅法的话,信号量就会加⼀,这⾥将//最新的信号量减去传进来的参数⽐较,⽐如有两个线程,其中⼀个线程已经调⽤了release⽅法,然后调⽤acquire(2)⽅法,那么//这⾥remaining的值就是-1,返回-1,然后当前线程就会被丢到阻塞队列中去了;如果另外⼀个线程也调⽤了release⽅法,//那么此时的remaining==0,所以在这⾥的if中会调⽤CAS将0设置到state//for (;;) {int available = getState();int remaining = available - acquires;if (remaining < 0 || compareAndSetState(available, remaining))return remaining;}//公平策略//和上⾯⾮公平差不多,只不过这⾥会查看阻塞队列中当前节点前⾯有没有前驱节点,有的话直接返回-1,//就会把当前线程丢到阻塞队列中阻塞去了,没有前驱节点的话,就跟⾮公平模式⼀样的了protected int tryAcquireShared(int acquires) {for (;;) {if (hasQueuedPredecessors())return -1;int available = getState();int remaining = available - acquires;if (remaining < 0 ||compareAndSetState(available, remaining))return remaining;}}再看看release(int permits)⽅法://这个⽅法的作⽤就是将信号量加⼀public void release(int permits) {if (permits < 0) throw new IllegalArgumentException();sync.releaseShared(permits);}//AQS中⽅法public final boolean releaseShared(int arg) {//tryReleaseShared尝试释放资源if (tryReleaseShared(arg)) {//释放资源成功就调⽤park⽅法唤醒唤醒AQS队列中最前⾯的节点中的线程doReleaseShared();return true;}return false;}protected final boolean tryReleaseShared(int releases) {//⼀个⽆限循环,获取state,然后加上传进去的参数,如果新的state的值⼩于旧的state,说明已经超过了state的最⼤值,溢出了//没有溢出的话,就⽤CAS更新state的值for (;;) {int current = getState();int next = current + releases;if (next < current) // overflowthrow new Error("Maximum permit count exceeded");if (compareAndSetState(current, next))return true;}}private void doReleaseShared() {for (;;) {Node h = head;if (h != null && h != tail) {int ws = h.waitStatus;//ws==Node.SIGNAL表⽰节点中线程需要被唤醒if (ws == Node.SIGNAL) {if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))continue; // loop to recheck cases//调⽤阻塞队列中线程的unpark⽅法唤醒线程unparkSuccessor(h);}//ws == 0表⽰节点中线程是初始状态else if (ws == 0 && !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))continue; // loop on failed CAS}if (h == head) // loop if head changedbreak;}} 以最上⾯的例⼦简单说⼀下,其实不是很难,⾸先线程1和线程2分别去调⽤release⽅法,这个⽅法⾥⾯会将AQS中的state加⼀,但是在执⾏这个操作之前,主线程肯定会先到acquire(2),在这个⽅法⾥⾯,假如默认使⽤⾮公平策略,⾸先获取当前的信号量state(state的初始值是0),⽤当前信号量减去2,如果⼩于0,那么当前主线程就会丢到AQS队列中阻塞; 这个时候线程1的release⽅法执⾏了,于是就把信号量state加⼀(此时state==1),CAS更新state为⼀,成功的话,就调⽤doReleaseShared()⽅法唤醒AQS阻塞队列中最先挂起的线程(这⾥就是因为调⽤acquire⽅法⽽阻塞的主线程),主线程唤醒之后⼜会去获取最新的信号量,与2⽐较,发现还是⼩于0,于是⼜会阻塞; 线程2此时的release⽅法执⾏完成,重复线程⼀的操作,主线程唤醒之后(此时state==2),⼜去获取最新的信号量发现是2,减去acquire⽅法的参数2等于0,于是就⽤CAS更新state的值,然后acquire⽅法也就执⾏完毕,主线程继续执⾏后⾯的代码; 其实信号量还是很有意思的,记得在项⽬⾥,有⼈利⽤信号量实现了⼀个故障隔离,什么时候我可以把整理之后的代码贴出来分享⼀下,还是很有意思的,就跟springcloud的熔断机制差不多,场景是:⽐如你在service的⼀个⽅法调⽤第三⽅的接⼝,你不知道调不调得通,⽽且你不希望每次前端过来都会去调⽤,⽐如当调⽤失败的次数超过100次,那么五分钟之后才会再去实际调⽤这个第三⽅服务!这五分钟内前调⽤这个服务,就会触发我们这个故障隔离的机制,向前端返回⼀个特定的错误码和错误信息!以上就是详解Java 信号量Semaphore的详细内容,更多关于Java 信号量Semaphore的资料请关注其它相关⽂章!。
java资源竞争问题,理解Semaphore及其用法详解
java资源竞争问题,理解Semaphore及其⽤法详解Semaphore也是⼀个线程同步的辅助类,可以维护当前访问⾃⾝的线程个数,并提供了同步机制。
使⽤Semaphore可以控制同时访问资源的线程个数,例如,实现⼀个⽂件允许的并发访问数。
Semaphore的主要⽅法摘要: void acquire():从此信号量获取⼀个许可,在提供⼀个许可前⼀直将线程阻塞,否则线程被中断。
void release():释放⼀个许可,将其返回给信号量。
int availablePermits():返回此信号量中当前可⽤的许可数。
boolean hasQueuedThreads():查询是否有线程正在等待获取。
代码⽰例:/** 防⽌同⼀台服务器上同时有多个⼈预约同⼀资源的同⼀⽇期* 形象解释: Semaphore机制类似⼀个服务⼤厅(最多容纳20⼈),这个服务⼤厅⾥⾯有多个服务窗⼝(每⼀天的资源场地):A、* B、C,这个服务⼤厅最多能进来20个⼈,进来的⼈都需要在各⾃需要办理的服务窗⼝排队等待,只有等到上⼀个⼈离* 开(释放信号)下⼀个⼈才能进⼊该服务窗⼝办理,但是各服务窗⼝之间是并⾏的互不影响。
*///⽤于控制访问量的信号变量,⼀次最多进⼊20个请求,按照先进先出许可private static Semaphore bookLockCounter = new Semaphore(20,true);try{//同⼀个应⽤服务内只允许20个⼈同时进⼊资源预定排队,否则报系统忙,请稍候再试。
if(bookLockCounter.getQueueLength() >= 20 || bookLockCounter.tryAcquire(500,LISECONDS) == false){throw new TzException("System is busy, please try again later.");}Semaphore tmpSemaphore = null;boolean hasPlanSemaphore = false; //记录成功获取信号,预定完成后需要释放try{//获取当资源⽇期对应的信号//⽤资源ID+⽇期来标识同⼀资源的同⼀⽇期,其他⼈在想预约这⼀资源就需要排队,但是预约其他资源的话就不⽤排队Map.Entry<String,Semaphore> tmpSemaphoreObject = tzGDObject.getSemaphore(tzms_class_addr_defn_tid + "-" +date);if(tmpSemaphoreObject == null || tmpSemaphoreObject.getKey() == null || tmpSemaphoreObject.getValue() == null){//如果返回的信号灯为空,报系统忙,请稍后再试(⼀般不会)throw new TzException("System is busy, please try again later.");}else{tmpSemaphore = tmpSemaphoreObject.getValue();//通过获取的信号将每个资源⽇期并⾏执⾏,资源⽇期内串⾏执⾏tmpSemaphore.acquire();//获取信号灯标记,预定完成后需要释放hasPlanSemaphore = true;}/*//////////////////////////////////////////////////////////////////////////////*//*/////////////////////此处开始执⾏预定的逻辑/////////////////////////////////////*//*//////////////////////////////////////////////////////////////////////////////*/} catch(TzException e) {e.printStackTrace();//预定失败,失败信息获取:e.getMessage()} finally {//释放资源信号量if(hasPlanSemaphore){tmpSemaphore.release();}//释放信号量bookLockCounter.release();}} catch(TzException e) {e.printStackTrace();}其中tzGDObject类中:// ⽤于将同⼀个服务上的并⾏访问串⾏化的信号灯映射变量private static HashMap<String, Semaphore> semaphoreMap = new HashMap<String, Semaphore>();// ⽤于将⽤于将同⼀个服务上的并⾏访问串⾏化的信号灯变量private static Semaphore sequenceSemaphore = new Semaphore(1, true);/*** 获取调⽤者信息的⽅法*/private String getCallerName() {String callerName = "";StackTraceElement tmpstack[] = Thread.currentThread().getStackTrace();boolean findFlag = false;for (StackTraceElement stackitem : tmpstack) {if ((stackitem.getClassName().indexOf(getClass().getName())) >= 0) {findFlag = true;} else if (findFlag == true) {callerName = stackitem.getClassName() + "." + stackitem.getMethodName();break;}}return callerName;}/*** 获取信号灯变量的⽅法*/public Map.Entry<String, Semaphore> getSemaphore(String semaphoreName) {Semaphore tmpSemaphore = null;String tmpSemaphoreName = getCallerName() + "-" + semaphoreName;System.out.println("successfully get the traffic light variable name[Thread ID : "+ Thread.currentThread().getId() + "]: " + tmpSemaphoreName);if (semaphoreMap.containsKey(tmpSemaphoreName) == true) {tmpSemaphore = semaphoreMap.get(tmpSemaphoreName);} else {try {// 获取信号灯,同步线程if (sequenceSemaphore.tryAcquire(100, LISECONDS) == false) {return null;}} catch (Exception e) {return null;}// 再次判断⼀下指定的信号灯是否已创建if (semaphoreMap.containsKey(tmpSemaphoreName) == true) {tmpSemaphore = semaphoreMap.get(tmpSemaphoreName);} else {tmpSemaphore = new Semaphore(1, true);semaphoreMap.put(tmpSemaphoreName, tmpSemaphore);}// 释放信号灯sequenceSemaphore.release();}HashMap<String, Semaphore> tmpHashMap = new HashMap<String, Semaphore>();tmpHashMap.put(tmpSemaphoreName, tmpSemaphore);return tmpHashMap.entrySet().iterator().next();}/*** 获取信号灯变量的⽅法,⽤于在两个不同的地⽅对同⼀个信号灯变量的控制,且调⽤该⽅法的参数相同 * @author zhanglang* @param semaphoreKey* @param semaphoreName* @return*/public Map.Entry<String, Semaphore> getSemaphore(String semaphoreKey, String semaphoreName) { Semaphore tmpSemaphore = null;String tmpSemaphoreName = "MULTI_" + semaphoreKey + "-" + semaphoreName;if (semaphoreMap.containsKey(tmpSemaphoreName) == true) {tmpSemaphore = semaphoreMap.get(tmpSemaphoreName);} else {try {// 获取信号灯,同步线程if (sequenceSemaphore.tryAcquire(100, LISECONDS) == false) {return null;}} catch (Exception e) {return null;}// 再次判断⼀下指定的信号灯是否已创建if (semaphoreMap.containsKey(tmpSemaphoreName) == true) {tmpSemaphore = semaphoreMap.get(tmpSemaphoreName);} else {tmpSemaphore = new Semaphore(1, true);semaphoreMap.put(tmpSemaphoreName, tmpSemaphore);}// 释放信号灯sequenceSemaphore.release();}HashMap<String, Semaphore> tmpHashMap = new HashMap<String, Semaphore>(); tmpHashMap.put(tmpSemaphoreName, tmpSemaphore);return tmpHashMap.entrySet().iterator().next();}。
JAVASemaphore详解
JAVASemaphore详解 Semaphore(信号量):是⼀种计数器,⽤来保护⼀个或者多个共享资源的访问。
如果线程要访问⼀个资源就必须先获得信号量。
如果信号量内部计数器⼤于0,信号量减1,然后允许共享这个资源;否则,如果信号量的计数器等于0,信号量将会把线程置⼊休眠直⾄计数器⼤于0.当信号量使⽤完时,必须释放。
实例代码:123 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 final Semaphore semaphore = new Semaphore(2);ExecutorService executorService = Executors.newCachedThreadPool();for(int i = 0; i < 10; i++) {final int index = i;executorService.execute(new Runnable() {public void run() {try{semaphore.acquire();System.out.println("线程:"+ Thread.currentThread().getName() + "获得许可:"+ index); TimeUnit.SECONDS.sleep(1);semaphore.release();System.out.println("允许TASK个数:"+ semaphore.availablePermits());} catch(InterruptedException e) {e.printStackTrace();}}});}executorService.shutdown(); 构造⽅法1:1 2 3public Semaphore(int permits) {sync = new NonfairSync(permits); } permits 初始许可数,也就是最⼤访问线程数构造⽅法2:1 2 3public Semaphore(int permits, boolean fair) {sync = (fair)? new FairSync(permits) : new NonfairSync(permits); } permits 初始许可数,也就是最⼤访问线程数 fair 当设置为false时,创建的信号量为⾮公平模式;当设置为true时,信号量是公平模式主要⽅法:void acquire() :从信号量获取⼀个许可,如果⽆可⽤许可前将⼀直阻塞等待,void acquire(int permits) :获取指定数⽬的许可,如果⽆可⽤许可前也将会⼀直阻塞等待boolean tryAcquire():从信号量尝试获取⼀个许可,如果⽆可⽤许可,直接返回false,不会阻塞boolean tryAcquire(int permits):尝试获取指定数⽬的许可,如果⽆可⽤许可直接返回falseboolean tryAcquire(int permits, long timeout, TimeUnit unit):在指定的时间内尝试从信号量中获取许可,如果在指定的时间内获取成功,返回true,否则返回falsevoid release():释放⼀个许可,别忘了在finally中使⽤,注意:多次调⽤该⽅法,会使信号量的许可数增加,达到动态扩展的效果,如:初始permits为1,调⽤了两次release,最⼤许可会改变为2int availablePermits():获取当前信号量可⽤的许可JDK ⾮公平Semaphore实现: 1.使⽤⼀个参数的构造创建Semaphore对象时,会创建⼀个NonfairSync对象实例,并将state值设为传⼊的值(permits ),1 2 3public Semaphore(int permits) {sync = new NonfairSync(permits); } NonfairSync间接的继承了AbstractQueuedSynchronizer实现12final static class NonfairSync extends Sync {2 3 4 5 6 7 8 9 10 11final static class NonfairSync extends Sync {private static final long serialVersionUID = -2694183684443567898L; NonfairSync(int permits) {super(permits);}protected int tryAcquireShared(int acquires) {return nonfairTryAcquireShared(acquires);}}1 2 3 4 5 6abstract static class Sync extends AbstractQueuedSynchronizer {private static final long serialVersionUID = 1192457210091910933L; Sync(int permits) {setState(permits);} AbstractQueuedSynchronizer 的setState⽅法1 2 3protected final void setState(int newState) { state = newState;} 2.调⽤tryAcquire⽅法时,实际是调⽤NonfairSync的nonfairTryAcquireShared⽅法,nonfairTryAcquireShared在⽗类Sync中实现,Semaphore# tryAcquire⽅法:1 2 3public boolean tryAcquire() {return sync.nonfairTryAcquireShared(1) >= 0; } Sync的nonfairTryAcquireShared⽅法1 2 3 4 5 6 7 8 9final int nonfairTryAcquireShared(int acquires) {for(;;) {int available = getState();int remaining = available - acquires;if(remaining < 0||compareAndSetState(available, remaining)) return remaining;}} nonfairTryAcquireShared ⽅法通过获取当前的state,以此state减去需要获取信号量的个数,作为剩余个数,如果结果⼩于0,返回此剩余的个数;如果结果⼤于等于0,则基于 CAS将state的值设置为剩余个数,当前步骤⽤到了for循环,所以只有在结果⼩于0或设置state值成功的情况下才会退出。
并发编程Semaphore的使用和详解
并发编程Semaphore的使⽤和详解类Semaphore的基本使⽤Semaphore的作⽤:限制线程并发的数量课外话题【多线程的同步概念】:其实就是排着队去执⾏⼀个任务,执⾏任务是⼀个⼀个的执⾏,这样的优点是有助于程序逻辑的正确性,不会出现⾮线程安全问题,保证⼈系统功能的运⾏稳定。
Semaphore类结构图:1、类Semaphore的构造函数permits 是许可的意思,代表同⼀时间,最多允许permits执⾏acquire() 和release() 之间的代码。
例如:Semaphore semaphore = new Semaphore(1);表⽰同⼀时间内最多只允许1个线程执⾏ acquire()和release()之间的代码。
2、⽅法acquire(n) 的功能是每调⽤1次此⽅法,就消耗掉n个许可。
3、⽅法release(n) 的功能是每调⽤1次此⽅法,就动态添加n个许可。
4、⽅法acquireUnnterruptibly()作⽤是是等待进⼊acquire() ⽅法的线程不允许被中断。
5、⽅法availablePermits() 返回Semaphore对象中当前可以⽤的许可数。
6、⽅法drainPermits() 获取并返回所有的许可个数,并且将可⽤的许可重置为07、⽅法 getQueueLength() 的作⽤是取得等待的许可的线程个数8、⽅法 hasQueueThreads() 的作⽤是判断有没有线程在等待这个许可9、公平和⾮公平信号量:有些时候获取许可的的顺序与线程启动的顺序有关,这是的信号量就要分为公平和⾮公平的。
所谓的公平信号量是获得锁的顺序与线程启动的顺序有关,但不代表100%获得信号量,仅仅是在概率上能保证,⽽⾮公平信号量就是⽆关的。
例如:Semaphore semaphore = new Semaphore(1,false);False:表⽰⾮公平信号量,即线程启动的顺序与调⽤semaphore.acquire() 的顺序⽆关,也就是线程先启动了并不代表先获得许可。
Java并发编程原理与实战二十八:信号量Semaphore
Java并发编程原理与实战⼆⼗⼋:信号量Semaphore 1.Semaphore简介Semaphore,是JDK1.5的java.util.concurrent并发包中提供的⼀个并发⼯具类。
所谓Semaphore即信号量的意思。
这个叫法并不能很好地表⽰它的作⽤,更形象的说法应该是许可证管理器。
其作⽤在JDK注释中是这样描述的:A counting semaphore.Conceptually, a semaphore maintains a set of permits.Each {@link #acquire} blocks if necessary until a permit is available, and then takes it.Each {@link #release} adds a permit, potentially releasing a blocking acquirer.However, no actual permit objects are used; the {@code Semaphore} just keeps a count of the number available and acts accordingly.翻译过来,就是:Semaphore是⼀个计数信号量。
从概念上将,Semaphore包含⼀组许可证。
如果有需要的话,每个acquire()⽅法都会阻塞,直到获取⼀个可⽤的许可证。
每个release()⽅法都会释放持有许可证的线程,并且归还Semaphore⼀个可⽤的许可证。
然⽽,实际上并没有真实的许可证对象供线程使⽤,Semaphore只是对可⽤的数量进⾏管理维护。
2.Semaphore⽅法说明Semaphore的⽅法如下:——Semaphore(permits)初始化许可证数量的构造函数——Semaphore(permits,fair)初始化许可证数量和是否公平模式的构造函数——isFair()是否公平模式FIFO——availablePermits()获取当前可⽤的许可证数量——acquire()当前线程尝试去阻塞的获取1个许可证。
.net core semaphore.waitone() 的原理
.net core semaphore.waitone() 的原理介绍如下:
在 .NET Core 中,Semaphore.WaitOne() 是一种同步机制,它可以协调多个线程的执行。
下面是Semaphore.WaitOne() 的工作原理:
1.当一个线程调用Semaphore.WaitOne() 方法时,它会尝试获得Semaphore 对象的
锁定。
2.如果Semaphore 对象当前没有被锁定,那么调用线程就会获得Semaphore 对象
的锁定,并继续执行后续的代码。
3.如果Semaphore 对象已经被锁定,则调用线程将会阻塞等待,直到Semaphore 对
象被释放为止。
4.当Semaphore 对象被释放时,其中一个阻塞线程将会被唤醒,并获得Semaphore
对象的锁定。
需要注意的是,Semaphore.WaitOne() 方法可以有一个可选的超时参数。
如果指定了超时参数,调用线程将只会等待指定的时间,如果Semaphore 对象没有被释放,则会自动放弃等待并返回false。
如果没有指定超时参数,则调用线程将一直等待,直到Semaphore 对象被释放为止。
Semaphore.WaitOne() 方法使用操作系统提供的信号量(Semaphore)实现。
当一个线程获得Semaphore 对象的锁定时,它会将Semaphore 对象的计数器减一。
当一个线程释放Semaphore 对象的锁定时,它会将Semaphore 对象的计数器加一。
当Semaphore 对象的计数器为零时,所有尝试获取Semaphore 对象的锁定的线程都会被阻塞。
semgrep java规则
semgrep java规则摘要:1.引言2.semgrep 简介3.semgrep java 规则4.如何使用semgrep java 规则5.semgrep java 规则的实际应用案例6.总结正文:semgrep 是一个功能强大的代码审计工具,可以帮助开发人员快速找到代码中的问题。
它支持多种编程语言,包括Java。
通过使用semgrep java 规则,开发人员可以更轻松地识别和解决Java 代码中的问题。
semgrep 使用正则表达式和grep 技术来搜索代码库中的特定模式。
它还可以使用预定义的规则集来检查代码是否符合最佳实践。
这些规则集可以由用户自定义,也可以从社区获取。
semgrep java 规则是针对Java 代码的一组预定义规则。
这些规则可以帮助开发人员识别潜在的安全漏洞、性能问题、代码质量问题等。
通过使用这些规则,开发人员可以更快地找到和修复代码中的问题,从而提高代码的质量和可靠性。
要使用semgrep java 规则,开发人员需要先安装semgrep 工具。
然后,他们可以使用以下命令来搜索Java 代码库中的特定模式:```semgrep -r -s java-rules.json path/to/your/code```其中,`java-rules.json`是包含semgrep java 规则的文件,`path/to/your/code`是要搜索的Java 代码库的路径。
semgrep java 规则的实际应用案例可以帮助开发人员更好地了解如何使用这些规则来解决实际问题。
例如,开发人员可以使用semgrep java 规则来检查代码中的SQL 注入风险、弱加密使用、不安全的文件操作等。
总之,semgrep java 规则是一个非常有用的工具,可以帮助开发人员快速找到和修复Java 代码中的问题。
rsemaphore详解
rsemaphore详解
RSemaphore,即Redisson的Semaphore,是一种非公平锁,其获取资源的顺序是不可预测的。
其主要作用是用来限制同时访问共享区域的线程数量,可以理解为分布式的信号量。
在使用RSemaphore时,需要先初始化并设置许可数量。
这通常是通过trySetPermits()方法来实现的,该方法尝试设置许可数量,如果设置成功,则返回true,否则返回false。
一旦设置了许可数量,就可以使用RSemaphore来控制对特定资源的访问。
这通常是通过acquire()方法来获取一个许可,以便访问资源。
如果当前没有可用的许可,那么acquire()方法将会阻塞,直到有一个许可可用为止。
需要注意的是,RSemaphore并不能保证对资源的公平访问,即不能保证按照线程请求的顺序来分配许可。
因此,在使用RSemaphore 时,需要考虑到这一点,以避免出现线程饥饿等问题。
总的来说,RSemaphore是一种非常有用的工具,可以用来控制对共享资源的并发访问,避免出现竞态条件等问题。
但是,在使用时需要注意其非公平性的特性,并合理地设置许可数量,以保证系统的稳定性和性能。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1.什么是Semaphore?A counting semaphore. Conceptually, a semaphore maintains a set of permits. Each acquire blocks ifnecessary until a permit is available, and then takes it. Each release adds a p ermit, potentially releasing ablocking acquirer. However, no actual permit objects are used; the Semaphore just keeps a count of thenumber available and acts accordingly.Semaphores are often used to restrict the number of threads than can access so me (physical or logical)resource.上面是官方给予该类的介绍,信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。
举个例子,公共厕所只有3个位子,有10个人要上厕所.一开始3个位都是空的,那么将有3个人先后占得坑,其它人只要在外面等待.如果有一个人上完厕所,然后等待中的7人中将有一个可以去上厕所.也有可能同时有两人OK,那么也将会同时有两人补位.简单说就是你必须有空位了,才能去上厕所.上厕所的例子虽不雅观,但令人印象深刻,本来想举ATM机取钱的例子的,但意思一样,还是举上厕所吧.Semaphore的作用就是控制位置的分配,一般情况下位置的分配是随机的,可以在实例化对象时设置规则进行排序.2.实例先看效果:再来看代码:package com.amos.concurrent;import java.util.Random;import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore;/*** @ClassName: SemaPhoreTest* @Description: 线程通信中的"信号灯"* @author: amosli* @email:hi_amos@* @date Apr 25, 2014 12:06:22 AM*/public class SemaPhoreTest {public static void main(String[] args) {ExecutorService threadPool =Executors.newCachedThreadPool();final Semaphore semaphore=new Semaphore(3);for(int i=0;i<10;i++){threadPool.execute(new Runnable() {public void run() {try{semaphore.acquire();//获取一个可用的permits} catch(Exception e) {e.printStackTrace();}System.out.println("线程" + Thread.currentThread().getN ame()+" 已进入. " + "目前已经有"+(3-semaphore.availablePermits())+" 个线程进入");try{Thread.sleep(new Random().nextInt(1000));} catch(InterruptedException e) {e.printStackTrace();} System.out.println("线程"+Thread.currentThread().getNam e()+ " 即将离开...");semaphore.release();//释放一个线程System.out.println("线程"+Thread.currentThread().getNam e()+ " 已离开. 当前有"+(3-semaphore.availablePermits())+"并发");}});}}}怎么保证是有序的?上面的代码是不保证顺序的,如果要有个先后顺序,即FIFO,先进先出原则,有个排队,上厕所要排队,只需要将上面的代码改掉一行即可.final Semaphore semaphore=new Semaphore(3, true);这样就可以了,其它代码不变.效果如下图所示:3.代码说明1).如何创建Semaphore?new Semaphore(3);//无序默认创建是无序的.new Semaphore(3,true);//有序2)如何获取一个"坑位"?首先,程序会先检查,"坑"是否已经满了,如果没满,那么可以按需分配,具体代码如下:try{semaphore.acquire();//获取一个可用的permits} catch(Exception e) {e.printStackTrace();}然后,分配完以后,将会把此坑位置为不可用了.3)如何释放一个"坑位"?semaphore.release();//释放一个线程释放完成以后将会把此坑位置为可用的.4.扩展--官方例子For example, here is a class that uses a semaphore to control access to a pool of items:class Pool {private static final int MAX_AVAILABLE = 100;private final Semaphore available = new Semaphore(MAX_AVAILABLE, tr ue);public Object getItem() throws InterruptedException {available.acquire();return getNextAvailableItem();}public void putItem(Object x) {if(markAsUnused(x))available.release();}// Not a particularly efficient data structure; just for demoprotected Object[] items =... whatever kinds of items being managedprotected boolean[] used = new boolean[MAX_AVAILABLE];protected synchronized Object getNextAvailableItem() {for(int i = 0; i < max_available; ++i) {if(!used[i]) {used[i] = true;return items[i];}}return null; // not reached}protected synchronized boolean markasunused(object item) {for(int i = 0; i < max_available; ++i) {if(item ==items[i]) {if(used[i]) {used[i] = false;return true;} elsereturn false;}}return false;}}java核心知识点学习----创建线程的第三种方式Callable和Future CompletionService前面已经指出通过实现Runnable时,Thread类的作用就是将run()方法包装成线程执行体,那么是否可以直接把任意方法都包装成线程执行体呢?Java目前不行,但其模仿者C#中是可以的.Callabel接口可以看成是Runnable接口的增强版,只不过其线程执行体call()方法比run 方法更加强大罢了:>>call()方法中可以有返回值>>call()方法中可以声明抛出异常.一.创建线程的第三种方式----使用Callable对象进行创建package com.amos.concurrent;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;/*** @ClassName: CallableAndFuture* @Description: 多线程中的Callable和Future学习* @author: amosli* @email:hi_amos@* @date Apr 22, 2014 12:07:26 AM*/public class CallableAndFuture {public static void main(String[] args) throws Exception, ExecutionException {ExecutorService newSingleThreadExecutor =Executors.newSingleThrea dExecutor();Future<String> future = newSingleThreadExecutor.submit(new Call able<String>() {public String call() throws Exception {Thread.sleep(20);return"hi,amos";}});// System.out.println("future:"+future.get(1,LISECONDS));/ /等待指定的时间System.out.println("future:" +future.get());}}效果如下:注:1.这里要注意的是,创建线程时执行任务不是用execute()方法去执行了,而是用submi t()方法.2.同时要注意,这里call()方法返回值,要和上面的保持一致.3.另外,可以设置最大等待时间,就是等待程序的返回值,这里使用get()方法.4.其常用的其它方法有cancel(),isCancelled(),isDone(),分别表示取消关联的任务,是否已经取消,任务是否已经完成.二.CompeltionServiceCompeltionService主要用于提交一组Callable对象,其take方法用于返回已完成的c allable任务的Future对象.可以用麦子收割来作比喻,种了10亩地的麦子,哪一块先成熟先收割哪一块.举例:package com.amos.concurrent;import java.util.Random;import java.util.concurrent.Callable;import pletionService;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorCompletionService;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class CallableAndFuture {public static void main(String[] args) throws Exception, ExecutionException {ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(10);CompletionService<Integer> completionService = new ExecutorCompl etionService<Integer>(newFixedThreadPool);for(int i=0;i<11;i++){//创建10个任务final int task=i;completionService.submit(new Callable<Integer>() {//提交任务public Integer call() throws Exception {Thread.sleep(new Random().nextInt(3000));//最多3秒return task;}});}//takefor(int i=0;i<11;i++){System.out.println("已完成的任务:"+completionService.take().get());}}效果如下图所示:注:由结果也可以看出来,其随机结果是根据任务的先后完成顺序来的,使用其take()方法可以获取其返回结果.。