自制Java中的Mutex类
同步问题中,一个很重要的问题是同步的域,什么是同步的域呢?简单以 synchronized 这个关键字来说,就是它所同步的范围。并发编程中很多时候出现的问题没有选好同步范围所导致的。但现有的同步关键字synchronized所能体现出来的对域的控制,估计用过的的人都应该感觉到并不是很理想。这个时候是不是很怀念Windows下所提供的Mutex操作,通过申请和释放的函数的位置控制同步的域,用起来要方便一些。
现在为了方便我们自己也可以做一个类似Windows的Mutex的类来方便我们对域的控制,下面看这个类的制作过程。
和制作上一个类一样,我们先来说一下希望这个类完成的功能:
1.调用getMutexFlag(),仅能是并发的线程中的一个继续执行,其余的阻塞。
2.调用freeMutexFlag(),执行的线程离开同步块(临界区),并能从阻塞线程中释放一个线程从getMutexFlag()中返回。
3.getMutexFlag()、freeMutexFlag(),都必须是原子操作。
上面这三个条件其实就是对Windows下Mutex的要求。
一开始我们也许会写出这样的代码:
package com.choi;
public class MutexFlag {
protected Thread currentThread = null;
public synchronized void getMutexFalg() {
if (currentThread == null) {
currentThread = Thread.currentThread();
}
while (currentThread != Thread.currentThread()) {
try {
wait();
if (currentThread == null) {
currentThread = Thread.currentThread();
}
} catch (Exception e) {
}
}
}
public synchronized void freeMutexFlag(){
if(currentThread!=null){
currentThread = null;
try {
notify();
} catch (Exception e) {
}
}
}
}
这段代码看起来是没有问题的,其实这段代码运行起来确实是没有问题的,但我们能把它提供给我们的项目组用吗?答案是不能的,我们来考虑一种情况:
项目组有三个程序员A,B,C。 A用这个类写了一个函数funA(get到Mutex未释放),B用这个类写了一个函数funB(get到Mutex未释放),C调用了funA,funB,用在一个线程中了。则这个线程运行到funA时得到了Mutex,运行到funB时再去申请Mutex能申请到吗?通过分析代码执行,肯定是NO。并申请不到,因为第一个还没有释放。Java里面如果是两个synchronized嵌套,则没有问题,第一个得到锁后,第二个如申请的是同一个锁,就会自动判断为已申请到。
我们可以用一个变量来是我们的MutexFlag实现synchronized的嵌套解决方案:
package com.choi;
public class MutexFlag {
protected Thread currentThread = null;
protected int count = ;
public synchronized void getMutexFalg() {
while (tryGetMutexFlag() == false) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized boolean tryGetMutexFlag() {
if (currentThread == null) {
currentThread = Thread.currentThread();
count = ;
return true;
}
if (currentThread == Thread.currentThread()) {
count++;
return true;
}
return false;
}
public synchronized void freeMutexFlag() {
if (currentThread == Thread.currentThread()) {
count--;
}
if (count == ) {
currentThread = null;
notify();
}
}
}
为了编写方便我把判断获取MutexFlag的代码写到了同步的tryGetMutexFlag中了,没申请成功一次就对count做加一操作,每一free都对count做减一操作,那么当count从新等于零的时候我们就去释放一个线程获取MutexFlag。
哦,有人说如果没有调用get就调用free会有问题,这里说明一下没有问题的,因为如果没有get,currentThread是等于null的,所以count==0,然后就会调用notify,其实没有问题啦,测试发现,notify不会抛出人异常,相当于空操作。
欢迎到我的GitHub主页获取代码:https://github.com/choitony/Java-MutexFlag-Class/tree/master
自制Java中的Mutex类的更多相关文章
- 带有静态方法的类(java中的math类)
带有静态方法的类通常(虽然不一定是这样)不打算被初始化. 可以用私有构造函数来限制非抽象类被初始化. 例如,java中的math类.它让构造函数标记为私有,所以你无法创建Math的实例.但Math类却 ...
- java中的File类
File类 java中的File类其实和文件并没有多大关系,它更像一个对文件路径描述的类.它即可以代表某个路径下的特定文件,也可以用来表示该路径的下的所有文件,所以我们不要被它的表象所迷惑.对文件的真 ...
- Java基础(43):Java中的Object类与其方法(转)
Object类 java.lang.Object java.lang包在使用的时候无需显示导入,编译时由编译器自动导入. Object类是类层次结构的根,Java中所有的类从根本上都继承自这个类. O ...
- java中基于TaskEngine类封装实现定时任务
主要包括如下几个类: 文章标题:java中基于TaskEngine类封装实现定时任务 文章地址: http://blog.csdn.net/5iasp/article/details/10950529 ...
- Java中的Unsafe类111
1.Unsafe类介绍 Unsafe类是在sun.misc包下,不属于Java标准.但是很多Java的基础类库,包括一些被广泛使用的高性能开发库都是基于Unsafe类开发的,比如Netty.Hadoo ...
- Java中遍历实体类(处理MongoDB)
在实际过程中,经常要将实体类进行封装,尤其是处理数据库的过程中:因此,对于遍历实体类能够与数据库中的一行数据对应起来. 我是使用的环境是Spring boot,访问的数据库时MongoDB 实体类遍历 ...
- java中遍历实体类,获取属性名和属性值
方式一(实体类): //java中遍历实体类,获取属性名和属性值 public static void testReflect(Object model) throws Exception{ for ...
- Java中的BigDecimal类精度问题
bigdecimal 能保证精度的原理是:BigDecimal的解决方案就是,不使用二进制,而是使用十进制(BigInteger)+小数点位置(scale)来表示小数,就是把所有的小数变成整数,记录小 ...
- java 中常用的类
java 中常用的类 Math Math 类,包含用于执行基本数学运算的方法 常用API 取整 l static double abs(double a) 获取double 的绝对值 l sta ...
随机推荐
- cocos2dx中快速完成一段可播放动画
版本:cocos2dx 2.2.6 IDE: VS2012 语言:C++98 CCSpriteFrameCache* cache = CCSpriteFrameCache::sharedSpriteF ...
- django之部署
布署 从uwsgi.nginx.静态文件三个方面处理 服务器介绍 服务器:私有服务器.公有服务器 私有服务器:公司自己购买.自己维护,只布署自己的应用,可供公司内部或外网访问 公有服务器:集成好运营环 ...
- JavaScript知识总结--对象的相关概念
一.定义 无序属性的集合. 说白了就是一个容器,可以容纳[基本值.对象或者函数],这些东西都叫做属性.每个属性都有一个名字,每个名字都映射一个值(可以是基本类型的值,也可以是引用类型的值).从以上描述 ...
- GNU/Linux操作系统总览
计算机科学本科的专业课包括高等数学.离散数学.模拟电子技术.数字电子技术.微机原理.汇编语言原理.高级程序语言.操作系统原理.高级编译原理.嵌入式原理.网络原理.计算机组成与结构等诸多科目.GNU计算 ...
- 我的Linux之路——实现虚拟机VMware上linux与windows互相复制与粘贴
出自:http://blog.csdn.net/u012243115/article/details/40454063 解决方法:只需要在CentOS安装一个vmware-tools的工具. 1.打开 ...
- Coursera连接不上(视频无法播放),修改hosts文件
视频问题 如果Coursera网站连接不上,或者视频加载不出来.可以通过如下方式进行配置: 一.找到hosts文件 Windows 系统, hosts文件位于: [C:\Windows\Syste ...
- shell编程——变量子串的常用操作
${#字符串} 返回字符串的长度 [root@localhost ~]# a=length [root@localhost ~]# echo ${#a} 6 ${字符串:位置x} 从位置x开始往后截取 ...
- golang之strings
针对golang中的字符串的介绍,提供了一些常用的函数和方法 package main import ( "fmt" "strings" ) func main ...
- Elasticsearch-PHP 安装
安装 Elasticsearch-PHP只有三个要求你需要担心: PHP 5.3.9 或更高版本(查看更多信息) Composer ext-curl: Libcurl的PHP扩展 其它的依赖会通过Co ...
- 使用net.sf.fjep.fatjar插件将第三方JAR包打包进自已的JAR包中
一般单个工程,在没有应用别人的jar包时导出为jar很简单,只要设置一个Main-Class就行了,也就是选择程序入口(main所在类).但是涉及到了数据库或需要用到第三方的JAR,就需要用到相应的数 ...