同步问题中,一个很重要的问题是同步的域,什么是同步的域呢?简单以 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类的更多相关文章

  1. 带有静态方法的类(java中的math类)

    带有静态方法的类通常(虽然不一定是这样)不打算被初始化. 可以用私有构造函数来限制非抽象类被初始化. 例如,java中的math类.它让构造函数标记为私有,所以你无法创建Math的实例.但Math类却 ...

  2. java中的File类

    File类 java中的File类其实和文件并没有多大关系,它更像一个对文件路径描述的类.它即可以代表某个路径下的特定文件,也可以用来表示该路径的下的所有文件,所以我们不要被它的表象所迷惑.对文件的真 ...

  3. Java基础(43):Java中的Object类与其方法(转)

    Object类 java.lang.Object java.lang包在使用的时候无需显示导入,编译时由编译器自动导入. Object类是类层次结构的根,Java中所有的类从根本上都继承自这个类. O ...

  4. java中基于TaskEngine类封装实现定时任务

    主要包括如下几个类: 文章标题:java中基于TaskEngine类封装实现定时任务 文章地址: http://blog.csdn.net/5iasp/article/details/10950529 ...

  5. Java中的Unsafe类111

    1.Unsafe类介绍 Unsafe类是在sun.misc包下,不属于Java标准.但是很多Java的基础类库,包括一些被广泛使用的高性能开发库都是基于Unsafe类开发的,比如Netty.Hadoo ...

  6. Java中遍历实体类(处理MongoDB)

    在实际过程中,经常要将实体类进行封装,尤其是处理数据库的过程中:因此,对于遍历实体类能够与数据库中的一行数据对应起来. 我是使用的环境是Spring boot,访问的数据库时MongoDB 实体类遍历 ...

  7. java中遍历实体类,获取属性名和属性值

    方式一(实体类): //java中遍历实体类,获取属性名和属性值 public static void testReflect(Object model) throws Exception{ for ...

  8. Java中的BigDecimal类精度问题

    bigdecimal 能保证精度的原理是:BigDecimal的解决方案就是,不使用二进制,而是使用十进制(BigInteger)+小数点位置(scale)来表示小数,就是把所有的小数变成整数,记录小 ...

  9. java 中常用的类

    java 中常用的类 Math Math 类,包含用于执行基本数学运算的方法 常用API 取整 l  static double abs(double  a) 获取double 的绝对值 l  sta ...

随机推荐

  1. Linux下sz下载文件超过4G办法

    当下载文件超过4G时,sz提示能下载. 解决办法有以下几种: 1.scp 2.ftp 3.nc 4.icmp 5.文件切割 ---------------------------------- 以上4 ...

  2. php中$_POST接收不到参数问题

    问题描述:PHP可以接收_GET._SERVER._COOKIE等参数,php://input可以读取没有处理过的POST数据,独独_POST接收不到post参数.  原因: php://input可 ...

  3. Tkinter Frame(框架)

       Tkinter Frame(框架): 框架构件在某种友好的方式进行分组和组织的其他部件的过程中是非常重要的.它就像一个容器,这是负责安排其他部件的位置   框架构件在某种友好的方式进行分组和组织 ...

  4. PHP5缓存插件

    1.1操作码介绍及缓存原理 当客户端请求一个PHP程序时,服务器的PHP引擎会解析到该PHP程序,并将其变异为特定的操作码文件(OperateCode opcode),这是要执行的PHP代码的一种二进 ...

  5. git之生成SSH key

    git之生成SSH key SSH 为 Secure Shell 的缩写,由 IETF 的网络小组(Network Working Group)所制定.利用 SSH 协议可以有效防止远程管理过程中的信 ...

  6. Unresolved external 'AlphaBlend' referenced from

    AlphaBlend [Linker Error] Unresolved external 'AlphaBlend' referenced from 解决方案 把文件msimg32.lib添加到工程中 ...

  7. LUA使用虚函数与使用回调函数

    ------------------虚函数overload-------------------------- --回调:寻路中格子坐标改变 CHero.OnSearchToCellsChange = ...

  8. java多线程-慎重使用volatile关键字

    Java语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量.这两种机制的提出都是为了实现代码线程的安全性.其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而 ...

  9. 搭建Git Server - Centos+Gitosis

    参考并部分转载自:http://www.pfeng.org/archives/757 1. 安装依赖 yum -y install curl-devel expat-devel gettext-dev ...

  10. 在Yii Framework中利用PHPMailer发送邮件(2011-06-02 14:06:23)

    转载▼ 标签: it 分类: 技术共享 官方扩展链接:http://www.yiiframework.com/extension/mailer/这个扩展配置十分方便,如果有问题的话,可以打开Debug ...