自制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 ...
随机推荐
- cinder-backup详细介绍
首先介绍Snapshot snapshot可以为volume创建快照,快照中保存了volume当前的状态,此后可以通过snapshot回溯 主要采用了Copy On Write算法.进行快照时,不牵涉 ...
- apache DOCUMENT_ROOT
问题描述:本地页面错误,+1上正常 本地及+1apache配置 <VirtualHost *:> ServerAdmin webmaster@dummy-host.example.com ...
- Django 组件-cookie 与 session
会话跟踪技术 1 什么是会话跟踪技术 我们需要先了解一下什么是会话!可以把会话理解为客户端与服务器之间的一次会晤,在一次会晤中可能会包含多次请求和响应.例如你给10086打个电话,你就是客户端,而10 ...
- Rhythmk 一步一步学 JAVA (13) Spring-2 之Ben懒加载以及生命周期,单例
1.定义Demo类: package com.rhythmk.spring; public class User { public void Init () { System.out.println( ...
- git之项目上传
git之项目上传 需求:将项目代码上传至github 前期准备: 1.github账号注册 2.安装git环境,可以打开且使用git shell. 3.生成SSH key并与github账号绑定 步骤 ...
- Installation failed with message Failed to finalize session : INSTALL_FAILED_INVALID_APK: Split lib_slice_8_apk was defined multiple times. It is possible that this issue is resolved by uninstalling a
取消:Instant Run就行
- 设置VS2010和IE8 调试ATL控件<转>
VS2010设置篇: 设置VS2010 通过IE8 调试ATL的ActiveX控件的步骤如下: 设置项目属性 在项目的属性页对话框中选中“配置属性—>调试”,在右边填入下列参数: 命令 ...
- 塔防游戏 Day2
1. 创建炮塔选择的 UI 使用 UI -> Toggle .注意指定同一 group. 2. 创建炮台的数据类 [System.Serializable] // 序列化 public clas ...
- A Bug's Life(加权并查集)
Description Background Professor Hopper is researching the sexual behavior of a rare species of bugs ...
- 附上SQL Server的存储过程例子
代码如下,看了就明白: --添加项目大类存储过程 use chaiqianD2 go if object_id('p_InsertBigType', 'p') is not null drop pro ...