15_张孝祥_多线程_Semaphere同步工具
2017-12-18 23:31
197 查看
java Semaphere可类比操作系统信号量,硬件资源如IO、内存、磁盘等都是有固定量的,多个程序需要竞争这些资源,没有资源就需要被挂起。
-参数 :
permits - 初始的可用许可数目。此值可能为负数,在这种情况下,必须在授予任何获取前进行释放。
public Semaphore(int permits, boolean fair):创建具有给定的许可数和给定的公平设置的 Semaphore。
-参数:
permits - 初始的可用许可数目。此值可能为负数,在这种情况下,必须在授予任何获取前进行释放。
fair - 如果此信号量保证在争用时按先进先出的顺序授予许可,则为 true;否则为 false。
void release():释放一个许可,将其返回给信号量。
int availablePermits():返回此信号量中当前可用的许可数。
boolean hasQueuedThreads():查询是否有线程正在等待获取。
信号量类似于锁机制,信号量的调用,当达到数量后,线程还是存在的,只是被挂起了而已。而线程池,同时执行的线程数量是固定的,超过了数量的只能等待。
输出:
可以同时有3个线程执行sp.acquire()到sp.release()之间的代码。
类和方法摘要
构造函数:
public Semaphore(int permits):创建具有给定的许可数和非公平的公平设置的 Semaphore。-参数 :
permits - 初始的可用许可数目。此值可能为负数,在这种情况下,必须在授予任何获取前进行释放。
public Semaphore(int permits, boolean fair):创建具有给定的许可数和给定的公平设置的 Semaphore。
-参数:
permits - 初始的可用许可数目。此值可能为负数,在这种情况下,必须在授予任何获取前进行释放。
fair - 如果此信号量保证在争用时按先进先出的顺序授予许可,则为 true;否则为 false。
常用方法:
void acquire():从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。void release():释放一个许可,将其返回给信号量。
int availablePermits():返回此信号量中当前可用的许可数。
boolean hasQueuedThreads():查询是否有线程正在等待获取。
使用技巧
将信号量初始化为 1,使得它在使用时最多只有一个可用的许可,从而可用作一个相互排斥的锁。这通常也称为二进制信号量,因为它只能有两种状态:一个可用的许可,或零个可用的许可。按此方式使用时,二进制信号量具有某种属性(与很多 Lock 实现不同),即可以由线程释放“锁”,而不是由所有者(因为信号量没有所有权的概念)。在某些专门的上下文(如死锁恢复)中这会很有用。对比线程池
线程池控制的是线程数量,而信号量控制的是并发数量,虽然说看起来一样,但两者还是有区别的。信号量类似于锁机制,信号量的调用,当达到数量后,线程还是存在的,只是被挂起了而已。而线程池,同时执行的线程数量是固定的,超过了数量的只能等待。
代码示例
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(); final Semaphore sp = new Semaphore(3); for(int i=0;i<10;i++){ Runnable runnable = new Runnable(){ public void run(){ try { 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(); //下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元 System.out.println("线程" + Thread.currentThread().getName() + "已离开,当前已有" + (3-sp.availablePermits()) + "个并发"); } }; service.execute(runnable); } } }
输出:
线程pool-1-thread-1进入,当前已有3个并发 线程pool-1-thread-3进入,当前已有3个并发 线程pool-1-thread-2进入,当前已有3个并发 线程pool-1-thread-1即将离开 线程pool-1-thread-1已离开,当前已有2个并发 线程pool-1-thread-4进入,当前已有3个并发 线程pool-1-thread-3即将离开 线程pool-1-thread-3已离开,当前已有2个并发 线程pool-1-thread-5进入,当前已有3个并发 线程pool-1-thread-4即将离开 线程pool-1-thread-4已离开,当前已有2个并发 线程pool-1-thread-6进入,当前已有3个并发 线程pool-1-thread-2即将离开 线程pool-1-thread-2已离开,当前已有2个并发 线程pool-1-thread-7进入,当前已有3个并发 线程pool-1-thread-7即将离开 线程pool-1-thread-7已离开,当前已有2个并发 线程pool-1-thread-8进入,当前已有3个并发 线程pool-1-thread-5即将离开 线程pool-1-thread-5已离开,当前已有3个并发 线程pool-1-thread-9进入,当前已有3个并发 线程pool-1-thread-6即将离开 线程pool-1-thread-6已离开,当前已有2个并发 线程pool-1-thread-10进入,当前已有3个并发 线程pool-1-thread-8即将离开 线程pool-1-thread-8已离开,当前已有2个并发 线程pool-1-thread-10即将离开 线程pool-1-thread-10已离开,当前已有1个并发 线程pool-1-thread-9即将离开 线程pool-1-thread-9已离开,当前已有0个并发
可以同时有3个线程执行sp.acquire()到sp.release()之间的代码。
相关文章推荐
- 10_张孝祥_多线程_Callable与Future的应用
- 16_张孝祥_多线程_同步工具CyclicBarrier与CountDownLatch
- 张孝祥java多线程视频笔记----线程范围内共享变量
- 【张孝祥并发课程笔记】06:多线程共享数据的方式探讨
- 孙鑫vc++ 15 (1)多线程与命名互斥
- vc++学习之15 多线程与聊天室程序的创建
- 学习java多线程的笔记4--传智播客_张孝祥_空中网挑选实习生的面试题(来源于视频)
- 从”JAVA“而终 15:java 多线程
- 张孝祥[致敬]-多线程学习第04课-线程的通信机制
- 02_张孝祥_Java多线程_传统定时器Timer
- python总结15 进程与多线程
- 17_张孝祥_多线程_同步工具Exchanger
- java学习笔记15--多线程编程基础2
- 孙鑫MFC笔记(15)--多线程和聊天室的创建
- 传智播客_张孝祥_Java基础5_多线程
- 张孝祥[致敬]-多线程学习第01课 传统线程的创建
- 张孝祥[致敬]-多线程学习第05课-线程范围内的共享变量
- 【Java多线程与并发库】15.java5的Exchanger同步工具
- 15.Java多线程
- 孙鑫VC++视频笔记(15)多线程与聊天室的创建