湖南网站建设企业,设计网站 f,微山网站建设公司,简历模板网站有哪些引言
本篇博客讲解《Java并发编程实战》中的同步工具类#xff1a;信号量 的使用和理解。
从概念、含义入手#xff0c;突出重点#xff0c;配以代码实例及讲解#xff0c;并以生活中的案例做类比加强记忆。
什么是信号量
Java中的同步工具类信号量即计数信号量#x…引言
本篇博客讲解《Java并发编程实战》中的同步工具类信号量 的使用和理解。
从概念、含义入手突出重点配以代码实例及讲解并以生活中的案例做类比加强记忆。
什么是信号量
Java中的同步工具类信号量即计数信号量Counting Semaphore是用来控制访问某个特定资源的操作数量或同时执行某个指定操作的数量。可以简单理解为信号量用来限制对某个资源的某种操作的数量。 一般用于实现某种资源池或对容器施加边界。 信号量管理着一组有限个数的虚拟许可permit而许可的数量就是限制特定操作数量的关键。
信号量的使用
前面已经说过信号量一般用于实现某种资源池或对容器施加边界这都是一个对特定操作的限制用途。那么想象一下如何限制操作的数量达到为一个再普通不过的容器施加边界的效果呢答案是给容器的某种操作可以是添加或删除元素应该广义的理解“某种操作”这个关键字眼增加一道执行许可只有在获得许可的情况下才可以执行这个操作 上图左边是普通的对容器的操作右边是有了信号量的对容器的操作。可以看出在增加了中间的信号量之后对容器的操作将会受限。
Semaphore
了解了信号量的大概含义那么进一步深入到Java类库的层面JDK为开发者提供了java.util.concurrent包下的Semaphore类它的含义就是上面所述的信号量管理着一组permit。
以“为容器施加边界”这一信号量用途为例。首先我们要明确一点使用信号量的方式来实现施加边界的方式其针对的是操作而不是容器的容量再一次重申是限制了操作而不是容器的容量
强调限制操作是为了要明白一点使用信号量来施加边界必然会对这个容器的某些操作进一步封装。比如添加方法就会在调用add之前先行调用Semaphore对象的acquire()方法在与这个操作相反的操作中去release()。并且acquire()方法是阻塞式的这就代表没有闲置许可的时候操作将会阻塞直到有许可被释放。
下面代码用信号量来对HashSet这个最普通的容器来施加一个添加限制进一步封装使其成为一个有界的阻塞式的容器。
public class BoundedHashSetT {private final SetT set;private final Semaphore sem;public BoundedHashSet(int bound) {this.set Collections.synchronizedSet(new HashSet());this.sem new Semaphore(bound);}public boolean add(T o) throws InterruptedException {sem.acquire();boolean wasAdded false;try {wasAdded set.add(o);return wasAdded;} finally {if (!wasAdded)sem.release();}}public boolean remove(Object o) {boolean wasRemoved set.remove(o);if (wasRemoved)sem.release();return wasRemoved;}/** 只是为了方便打印的 */public void print() {System.out.print(Thread.currentThread().getName() : );this.set.forEach(o - System.out.print(o ));}/** 用于测试的主方法 */public static void main(String[] args) {BoundedHashSetString names new BoundedHashSet(5);new Thread(() - {for (int i 0; i 100; i) {try {names.add(name i);names.print();System.out.println();TimeUnit.SECONDS.sleep(1);} catch (Exception e) {e.printStackTrace();}}}, TH-ADD).start();new Thread(() - {for (int i 0; i 100; i) {System.out.println(Thread.currentThread().getName() --------执行清理删除name i);names.remove(name i);try {TimeUnit.SECONDS.sleep(10);} catch (Exception e) {e.printStackTrace();}}},TH-REMOVE).start();}
}
执行结果如下 我们用一个线程为这个“有界”容器每隔1秒钟添加一个元素然后另一个线程每隔10秒钟移除一个元素。且初始化了这个容器的信号量为5那么当容器中添加元素的数量达到5之后5个许可全部被占用添加操作将进入阻塞状态直到remove的时候释放一个许可才可以继续添加元素。从上述结果可以看出两点
1、拥有5个许可的信号量成功的限制了容器的元素个数即为容器施加了一个边界
2、添加的操作在没有获得许可的情况下将进入阻塞状态在执行的过程中也恰恰印证了这一点当remove执行并release()之后添加操作会立刻执行。
生活中的类比
其实这个类比博主认为从严谨的角度来讲并不是完全符合信号量的概念但是我们可以类比的同时找出不同点不仅有效的通过生活案例理解了信号量还对与之不同的地方增加了深刻的印象所以还是决定拿出来供大家参考。
上过学的同学可能都知道学校有奖学金制度。虽然我没怎么得过奖学金但是大概的逻辑还是比较好理解。
学校的奖学金制度是怎样的呢 学校每年都会给全校的学生指定数量的全额奖学金名额比如全额奖学金5名。那么如果想获得全额奖学金就必须先获得名额才行。 从这个简单的逻辑我们可以找出关键的与信号量中的概念相匹配的内容 奖学金 特定资源 获得奖学金 指定操作如remove操作 名额 一组定额许可的信号量 名额已满来年再报 操作阻塞等待释放许可 有了上面的等式信号量的神秘面纱就算彻底被我们揭开了原来它就是一个管理一组定额许可的通行证要想执行操作那就必须先得到许可否则就阻塞。
总结
信号量的概念限制操作数量。
一个类Semaphore 两个方法acquire()、release()。
用途对容器施加边界对容器的操作的再封装。
另外奖学金和信号量之间的类比并不完全匹配不过这种程度的类比已经相当清晰至于哪些信息有所差异留给各位看官自己去挖掘。如果有什么新的发现真诚希望在博客下方留言。
愿所有热爱编程的开发者共同进步