博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JAVA多线程提高九:Semaphere同步工具
阅读量:5077 次
发布时间:2019-06-12

本文共 3257 字,大约阅读时间需要 10 分钟。

java 中Semaphere可类比操作系统信号量,硬件资源如IO、内存、磁盘等都是有固定量的,多个程序需要竞争这些资源,没有资源就需要被挂起。

一、类和方法摘要

构造函数:

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()之间的代码。

 

参考资料:

<<Java多线程与并发库高级应用>> 张孝祥 视频

 

转载于:https://www.cnblogs.com/pony1223/p/9303009.html

你可能感兴趣的文章
react展示数据
查看>>
测试计划
查看>>
选择器
查看>>
Mysql与Oracle 的对比
查看>>
jquery实现限制textarea输入字数
查看>>
thinkphp5 csv格式导入导出(多数据处理)
查看>>
PHP上传RAR压缩包并解压目录
查看>>
Codeforces 719B Anatoly and Cockroaches
查看>>
jenkins常用插件汇总
查看>>
c# 泛型+反射
查看>>
第九章 前后查找
查看>>
Python学习资料
查看>>
jQuery 自定义函数
查看>>
jquery datagrid 后台获取datatable处理成正确的json字符串
查看>>
ActiveMQ与spring整合
查看>>
web服务器
查看>>
网卡流量检测.py
查看>>
poj1981 Circle and Points 单位圆覆盖问题
查看>>
POP的Stroke动画
查看>>
SQL语句在查询分析器中可以执行,代码中不能执行
查看>>