- 浏览: 954712 次
文章分类
- 全部博客 (428)
- Hadoop (2)
- HBase (1)
- ELK (1)
- ActiveMQ (13)
- Kafka (5)
- Redis (14)
- Dubbo (1)
- Memcached (5)
- Netty (56)
- Mina (34)
- NIO (51)
- JUC (53)
- Spring (13)
- Mybatis (17)
- MySQL (21)
- JDBC (12)
- C3P0 (5)
- Tomcat (13)
- SLF4J-log4j (9)
- P6Spy (4)
- Quartz (12)
- Zabbix (7)
- JAVA (9)
- Linux (15)
- HTML (9)
- Lucene (0)
- JS (2)
- WebService (1)
- Maven (4)
- Oracle&MSSQL (14)
- iText (11)
- Development Tools (8)
- UTILS (4)
- LIFE (8)
最新评论
-
Donald_Draper:
Donald_Draper 写道刘落落cici 写道能给我发一 ...
DatagramChannelImpl 解析三(多播) -
Donald_Draper:
刘落落cici 写道能给我发一份这个类的源码吗Datagram ...
DatagramChannelImpl 解析三(多播) -
lyfyouyun:
请问楼主,执行消息发送的时候,报错:Transport sch ...
ActiveMQ连接工厂、连接详解 -
ezlhq:
关于 PollArrayWrapper 状态含义猜测:参考 S ...
WindowsSelectorImpl解析一(FdMap,PollArrayWrapper) -
flyfeifei66:
打算使用xmemcache作为memcache的客户端,由于x ...
Memcached分布式客户端(Xmemcached)
AtomicInteger解析:http://donald-draper.iteye.com/blog/2359555
锁持有者管理器AbstractOwnableSynchronizer:http://donald-draper.iteye.com/blog/2360109
AQS线程挂起辅助类LockSupport:http://donald-draper.iteye.com/blog/2360206
AQS详解-CLH队列,线程等待状态:http://donald-draper.iteye.com/blog/2360256
AQS-Condition详解:http://donald-draper.iteye.com/blog/2360381
可重入锁ReentrantLock详解:http://donald-draper.iteye.com/blog/2360411
CountDownLatch使用场景:http://donald-draper.iteye.com/blog/2348106
CountDownLatch详解:http://donald-draper.iteye.com/blog/2360597
CyclicBarrier详解:http://donald-draper.iteye.com/blog/2360812
Semaphore 是一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个acquire(),然后再获取该许可。每个release() 添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。说白了,Semaphore是一个计数器,在计数器不为0的时候对线程就放行,一旦达到0,那么所有请求资源的新线程都会被阻塞,包括增加请求到许可的线程,也就是说Semaphore不是可重入的。每一次请求一个许可都会导致计数器减少1,同样每次释放一个许可都会导致计数器增加1,一旦达到了0,新的许可请求线程将被挂起。缓存池整好使用此思想来实现的,比如链接池、对象池等。
下面来看一个实例:
ObjectCache描述了一个基于信号量Semaphore的对象池实现。此对象池最多支持capacity个对象,这在构造函数中传入。对象池有一个基于FIFO的队列,每次从对象池的头结点开始取对象,如果头结点为空就直接构造一个新的对象返回。否则将头结点对象取出,并且头结点往后移动。特别要说明的如果对象的个数用完了,那么新的线程将被阻塞,直到有对象被返回回来。返还对象时将对象加入FIFO的尾节点并且释放一个空闲的信号量,表示对象池中增加一个可用对象。实际上对象池、线程池的原理大致上就是这样的,只不过真正的对象池、线程池要处理比较复杂的逻辑,所以实现起来还需要做很多的工作,例如超时机制,自动回收机制,对象的有效期等等问题。这里特别说明的是信号量只是在信号不够的时候挂起线程,但是并不能保证信号量足够的时候获取对象和返还对象是线程安全的,所以在示例中仍然需要锁Lock来保证并发的正确性。将信号量初始化为1,使得它在使用时最多只有一个可用的许可,从而可用作一个相互排斥的锁。这通常也称为二进制信号量,因为它只能有两种状态:一个可用的许可,或零个可用的许可。按此方式使用时,二进制信号量具有某种属性(与很多Lock 实现不同),即可以由线程释放“锁”,而不是由所有者(因为信号量没有所有权的概念)。在某些专门的上下文(如死锁恢复)中这会很有用。上面这段话的意思是说当某个线程A持有信号量数为1的信号量时,其它线程只能等待此线程释放资源才能继续,这时候持有信号量的线程A就相当于持有了“锁”,其它线程的继续就需要这把锁,于是线程A的释放才能决定其它线程的运行,相当于扮演了“锁”的角色。另外同公平锁非公平锁一样,信号量也有公平性。如果一个信号量是公平的表示线程在获取信号量时按FIFO的顺序得到许可,也就是按照请求的顺序得到释放。这里特别说明的是:所谓请求的顺序是指在请求信号量而进入FIFO队列的顺序,
有可能某个线程先请求信号而后进去请求队列,那么次线程获取信号量的顺序就会晚于其后请求但是先进入请求队列的线程。这个在公平锁和非公平锁中谈过很多。
锁持有者管理器AbstractOwnableSynchronizer:http://donald-draper.iteye.com/blog/2360109
AQS线程挂起辅助类LockSupport:http://donald-draper.iteye.com/blog/2360206
AQS详解-CLH队列,线程等待状态:http://donald-draper.iteye.com/blog/2360256
AQS-Condition详解:http://donald-draper.iteye.com/blog/2360381
可重入锁ReentrantLock详解:http://donald-draper.iteye.com/blog/2360411
CountDownLatch使用场景:http://donald-draper.iteye.com/blog/2348106
CountDownLatch详解:http://donald-draper.iteye.com/blog/2360597
CyclicBarrier详解:http://donald-draper.iteye.com/blog/2360812
Semaphore 是一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个acquire(),然后再获取该许可。每个release() 添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。说白了,Semaphore是一个计数器,在计数器不为0的时候对线程就放行,一旦达到0,那么所有请求资源的新线程都会被阻塞,包括增加请求到许可的线程,也就是说Semaphore不是可重入的。每一次请求一个许可都会导致计数器减少1,同样每次释放一个许可都会导致计数器增加1,一旦达到了0,新的许可请求线程将被挂起。缓存池整好使用此思想来实现的,比如链接池、对象池等。
下面来看一个实例:
package juc.latch; import java.util.concurrent.Semaphore; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 信号量实现的对象池 * @author donald * 2017年3月6日 * 下午9:43:06 * @param <T> */ public class ObjectCache<T> { //对象工厂 public interface ObjectFactory<T> { T makeObject(); } //将对象封装节点中,放到一个先进先出的队列中,即对象池 class Node { T obj; Node next; } final int capacity;//线程次容量 final ObjectFactory<T> factory; final Lock lock = new ReentrantLock();//保证对象获取,释放的线程安全 final Semaphore semaphore;//信号量 private Node head; private Node tail; public ObjectCache(int capacity, ObjectFactory<T> factory) { this.capacity = capacity; this.factory = factory; this.semaphore = new Semaphore(this.capacity); this.head = null; this.tail = null; } /** * 从对象池中,获取对象 * @return * @throws InterruptedException */ public T getObject() throws InterruptedException { semaphore.acquire(); return getObjectFromPool(); } /** * 线程安全地从对象池获取对象 * @return */ private T getObjectFromPool() { lock.lock(); try { if (head == null) { return factory.makeObject(); } else { Node ret = head; head = head.next; if (head == null) tail = null; ret.next = null;// help GC return ret.obj; } } finally { lock.unlock(); } } /** * 线程安全地,将对象放回对象池 * @param t */ private void putBackObjectToPool(T t) { lock.lock(); try { Node node = new Node(); node.obj = t; if (tail == null) { head = tail = node; } else { tail.next = node; tail = node; } } finally { lock.unlock(); } } /** * 将对象放回对象池 * @param t */ public void putBackObject(T t) { putBackObjectToPool(t); semaphore.release(); } }
ObjectCache描述了一个基于信号量Semaphore的对象池实现。此对象池最多支持capacity个对象,这在构造函数中传入。对象池有一个基于FIFO的队列,每次从对象池的头结点开始取对象,如果头结点为空就直接构造一个新的对象返回。否则将头结点对象取出,并且头结点往后移动。特别要说明的如果对象的个数用完了,那么新的线程将被阻塞,直到有对象被返回回来。返还对象时将对象加入FIFO的尾节点并且释放一个空闲的信号量,表示对象池中增加一个可用对象。实际上对象池、线程池的原理大致上就是这样的,只不过真正的对象池、线程池要处理比较复杂的逻辑,所以实现起来还需要做很多的工作,例如超时机制,自动回收机制,对象的有效期等等问题。这里特别说明的是信号量只是在信号不够的时候挂起线程,但是并不能保证信号量足够的时候获取对象和返还对象是线程安全的,所以在示例中仍然需要锁Lock来保证并发的正确性。将信号量初始化为1,使得它在使用时最多只有一个可用的许可,从而可用作一个相互排斥的锁。这通常也称为二进制信号量,因为它只能有两种状态:一个可用的许可,或零个可用的许可。按此方式使用时,二进制信号量具有某种属性(与很多Lock 实现不同),即可以由线程释放“锁”,而不是由所有者(因为信号量没有所有权的概念)。在某些专门的上下文(如死锁恢复)中这会很有用。上面这段话的意思是说当某个线程A持有信号量数为1的信号量时,其它线程只能等待此线程释放资源才能继续,这时候持有信号量的线程A就相当于持有了“锁”,其它线程的继续就需要这把锁,于是线程A的释放才能决定其它线程的运行,相当于扮演了“锁”的角色。另外同公平锁非公平锁一样,信号量也有公平性。如果一个信号量是公平的表示线程在获取信号量时按FIFO的顺序得到许可,也就是按照请求的顺序得到释放。这里特别说明的是:所谓请求的顺序是指在请求信号量而进入FIFO队列的顺序,
有可能某个线程先请求信号而后进去请求队列,那么次线程获取信号量的顺序就会晚于其后请求但是先进入请求队列的线程。这个在公平锁和非公平锁中谈过很多。
发表评论
-
Executors解析
2017-04-07 14:38 1204ThreadPoolExecutor解析一(核心线程池数量、线 ... -
ScheduledThreadPoolExecutor解析三(关闭线程池)
2017-04-06 20:52 4413ScheduledThreadPoolExecutor解析一( ... -
ScheduledThreadPoolExecutor解析二(任务调度)
2017-04-06 12:56 2076ScheduledThreadPoolExecutor解析一( ... -
ScheduledThreadPoolExecutor解析一(调度任务,任务队列)
2017-04-04 22:59 4922Executor接口的定义:http://donald-dra ... -
ThreadPoolExecutor解析四(线程池关闭)
2017-04-03 23:02 9039Executor接口的定义:http: ... -
ThreadPoolExecutor解析三(线程池执行提交任务)
2017-04-03 12:06 6031Executor接口的定义:http://donald-dra ... -
ThreadPoolExecutor解析二(线程工厂、工作线程,拒绝策略等)
2017-04-01 17:12 2990Executor接口的定义:http://donald-dra ... -
ThreadPoolExecutor解析一(核心线程池数量、线程池状态等)
2017-03-31 22:01 20468Executor接口的定义:http://donald-dra ... -
ScheduledExecutorService接口定义
2017-03-29 12:53 1455Executor接口的定义:http://donald-dra ... -
AbstractExecutorService解析
2017-03-29 08:27 1024Executor接口的定义:http: ... -
ExecutorCompletionService解析
2017-03-28 14:27 1527Executor接口的定义:http://donald-dra ... -
CompletionService接口定义
2017-03-28 12:39 1011Executor接口的定义:http://donald-dra ... -
FutureTask解析
2017-03-27 12:59 1283package java.util.concurrent; ... -
Future接口定义
2017-03-26 09:40 1131/* * Written by Doug Lea with ... -
ExecutorService接口定义
2017-03-25 22:14 1119Executor接口的定义:http://donald-dra ... -
Executor接口的定义
2017-03-24 23:24 1605package java.util.concurrent; ... -
简单测试线程池拒绝执行任务策略
2017-03-24 22:37 1965线程池多余任务的拒绝执行策略有四中,分别是直接丢弃任务Disc ... -
JAVA集合类简单综述
2017-03-23 22:51 878Queue接口定义:http://donald-draper. ... -
DelayQueue解析
2017-03-23 11:00 1682Queue接口定义:http://donald-draper. ... -
SynchronousQueue解析下-TransferQueue
2017-03-22 22:20 2090Queue接口定义:http://donald-draper. ...
相关推荐
目录: 简介 1.1 并发编程与资源控制 1.2 Semaphore概述 Semaphore的基本用法 2.1 创建Semaphore对象 ...4.2 使用Semaphore实现有界资源池 Semaphore的公平性 5.1 非公平性 5.2 公平性 最佳实践与注意事项
25.5.对象池示例 25.5.1.实现Spring.Pool.IPoolableObjectFactory 25.5.2.使用池中的对象 25.5.3.利用executor执行并行的grep 25.6.AOP 第二十六章. AOP指南 26.1.简介 26.2.基础知识 26.2.1.应用通知 26.2.2.使用...
Redisson-Redis Java客户端具有内存中数据网格的功能 | | | | | 基于高性能的异步和无锁Java Redis客户端和框架。...对象持有人,二进制流持有人,地理空间持有人,BitSet,AtomicLong,AtomicDouble,Publish
信号量(Semaphore)是由内核对象维护的int变量,当信号量为0时,在信号量上等待的线程会堵塞,信号量大于0时,就解除堵塞。当在一个信号量上等待的线程解除堵塞时,内核自动会将信号量的计数减1。在.net 下通过...
13.9 用显式接口方法实现来增强编译时类型安全性 13.10 谨慎使用显式接口方法实现 13.11 设计:基类还是接口? 第14章 字符、字符串和文本处理 14.1 字符 14.2 System.String类型 14.2.1 构造字符串 14.2.2 ...
(2)实现资源池,例如数据库连接池 (3)使用信号量将任何一种容器变成有界阻塞容器 栅栏 能够阻塞一组线程直到某个事件发生 栅栏和闭锁的区别 所有线程必须同时到达栅栏位置,...
13.9 用显式接口方法实现来增强编译时类型安全性 13.10 谨慎使用显式接口方法实现 13.11 设计:基类还是接口? 第14章 字符、字符串和文本处理 14.1 字符 14.2 System.String类型 14.2.1 构造字符串 14.2.2 ...
13.9 用显式接口方法实现来增强编译时类型安全性 13.10 谨慎使用显式接口方法实现 13.11 设计:基类还是接口? 第14章 字符、字符串和文本处理 14.1 字符 14.2 System.String类型 14.2.1 构造字符串 14.2.2 ...
13.9 用显式接口方法实现来增强编译时类型安全性 13.10 谨慎使用显式接口方法实现 13.11 设计:基类还是接口? 第14章 字符、字符串和文本处理 14.1 字符 14.2 System.String类型 14.2.1 构造字符串 14.2.2 ...
序列化和反序列化对象(将不长用的对象暂时持久化到文件中为对象的序列化,反之用时再把对象恢复到内存为反序列化); 控制对象的序列化和反序列化; 读jar包的资源文件;用zip格式压缩 和解压文件;操作Excel文件;...
ReiserRT_Core Frank Reiser的C ++ 11核心组件,用于多线程实时嵌入式系统。...对象池 在实时应用程序中调用new和delete可能会严重影响确定性。 ObjectPool提供预先分配的内存,用于一定数量的某些基本类型的对象。 其
11.4.7 向对象池说“不”200 11.5 示例:比较Map的性能200 11.6 减少上下文切换的开销201 第12章 并发程序的测试204 12.1 正确性测试205 12.1.1 基本的单元测试206 12.1.2 对阻塞操作的测试207 12.1.3 安全...
Semaphore对象会在对象回收时进行销毁 进程池start()后,需要调用wait()进行僵尸进程回收,可以无阻塞调用 获取进程状态(调用isAlive()方法)前,最好调用一个无阻塞的wait(false)进行...