自制Java中的Mutex类
2015-07-27 18:03
579 查看
同步问题中,一个很重要的问题是同步的域,什么是同步的域呢?简单以 synchronized 这个关键字来说,就是它所同步的范围。并发编程中很多时候出现的问题没有选好同步范围所导致的。但现有的同步关键字synchronized所能体现出来的对域的控制,估计用过的的人都应该感觉到并不是很理想。这个时候是不是很怀念Windows下所提供的Mutex操作,通过申请和释放的函数的位置控制同步的域,用起来要方便一些。
现在为了方便我们自己也可以做一个类似Windows的Mutex的类来方便我们对域的控制,下面看这个类的制作过程。
和制作上一个类一样,我们先来说一下希望这个类完成的功能:
1.调用getMutexFlag(),仅能是并发的线程中的一个继续执行,其余的阻塞。
2.调用freeMutexFlag(),执行的线程离开同步块(临界区),并能从阻塞线程中释放一个线程从getMutexFlag()中返回。
3.getMutexFlag()、freeMutexFlag(),都必须是原子操作。
上面这三个条件其实就是对Windows下Mutex的要求。
一开始我们也许会写出这样的代码:
这段代码看起来是没有问题的,其实这段代码运行起来确实是没有问题的,但我们能把它提供给我们的项目组用吗?答案是不能的,我们来考虑一种情况:
项目组有三个程序员A,B,C。 A用这个类写了一个函数funA(get到Mutex未释放),B用这个类写了一个函数funB(get到Mutex未释放),C调用了funA,funB,用在一个线程中了。则这个线程运行到funA时得到了Mutex,运行到funB时再去申请Mutex能申请到吗?通过分析代码执行,肯定是NO。并申请不到,因为第一个还没有释放。Java里面如果是两个synchronized嵌套,则没有问题,第一个得到锁后,第二个如申请的是同一个锁,就会自动判断为已申请到。
我们可以用一个变量来是我们的MutexFlag实现synchronized的嵌套解决方案:
为了编写方便我把判断获取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
现在为了方便我们自己也可以做一个类似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 = 0; 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 = 1; return true; } if (currentThread == Thread.currentThread()) { count++; return true; } return false; } public synchronized void freeMutexFlag() { if (currentThread == Thread.currentThread()) { count--; } if (count == 0) { 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笔记之线程池
- java.lang.OutOfMemoryError: Java heap space解决方案
- 如何对生产环境的JAVA应用进行远程调试
- eclipse 基本设置
- java单点登录系统CAS的简单使用
- Spring配置事务中的 transactionAttributes 各属性含义
- CXF实战之集成Spring(三)
- java中包的作用以及权限问题
- struts1、struts2 遍历map<String,List<TItem>>
- MyEclipse 8.6 更新安装 maven插件
- 生成MyEclipse6.5&7.5&8.0注册码的java源码
- JAVA里的别名机制
- java工厂模式
- Java内存模型
- java集群优化——ORM框架查询优化原理
- JAVA中变量的类型及命名规范
- Spring -- 4.0新特性 -- 泛型依赖注入
- JAVA--多线程基础
- window7 jdk环境变量配置
- JDK/JRE/SERVER/CLIENT/JAVA/JAVAC/JAVAW等等