自制Java中的Mutex类

同步问题中,一个很重要的问题是同步的域,什么是同步的域呢?简单以 synchronized 这个关键字来说,就是它所同步的范围。并发编程中很多时候出现的问题没有选好同步范围所导致的。但现有的同步关键字synchronized所能体现出来的对域的控制,估计用过的的人都说不是很理想。这个时候是不是很怀念Windows下所提供的Mutex操作。

现在为了方便我们自己也可以做一个类似Windows的Mutex的类来方便我们对域的控制,下面看这个类的制作过程。

和制作上一个类一样,我们先来说一下希望这个类完成的功能:

1.调用getMutexFlag(),仅能是并发的线程中的一个继续执行,其余的阻塞。

2.调用freeMutexFlag(),执行的线程离开同步块(临界区),并能从阻塞线程中释放一个线程从getMutexFlag()中返回。

3.getMutexFlag()、freeMutexFlag(),都必须是原子操作。

上面这三个条件其实就是对Windows下Mutex的要求。

已开始我们也许会写出这样的代码:

 1 package com.choi;
 2
 3 public class MutexFlag {
 4
 5     protected Thread currentThread = null;
 6
 7     public synchronized void getMutexFalg() {
 8         if (currentThread == null) {
 9             currentThread = Thread.currentThread();
10         }
11         while (currentThread != Thread.currentThread()) {
12             try {
13                 wait();
14                 if (currentThread == null) {
15                     currentThread = Thread.currentThread();
16                 }
17             } catch (Exception e) {
18             }
19         }
20     }
21
22     public synchronized void freeMutexFlag(){
23         if(currentThread!=null){
24             currentThread = null;
25             try {
26                 notify();
27             } catch (Exception e) {
28             }
29         }
30     }
31 }

这段代码看起来是没有问题的,其实这段代码运行起来确实是没有问题的,但我们能把它提供给我们的项目组用吗?答案是不能的,我们来考虑一种情况:

项目组有三个程序员A,B,C A用这个类写了一个函数(get到Mutex未释放),B用这个类写了一个函数(get到Mutex未释放),C调用了A和B的函数,用在一个线程中了。则这个线程运行到A时得到了Mutex,运行到B时再去申请Mutex能申请到吗?看代码,回答是NO。并申请不到,因为第一个还没有释放。Java里面如果是两个synchronized嵌套,则没有问题,第一个得到锁后,第二个如申请的是同一个锁,就会自动判断为已申请到。

我们可以用一个变量来是我们的MutexFlag实现synchronized的嵌套解决方案:

 1 package com.choi;
 2
 3 public class MutexFlag {
 4
 5     protected Thread currentThread = null;
 6     protected int count = 0;
 7
 8     public synchronized void getMutexFalg() {
 9         while (tryGetMutexFlag() == false) {
10             try {
11                 wait();
12             } catch (InterruptedException e) {
13                 e.printStackTrace();
14             }
15         }
16     }
17
18     public synchronized boolean tryGetMutexFlag() {
19         if (currentThread == null) {
20             currentThread = Thread.currentThread();
21             count = 1;
22             return true;
23         }
24         if (currentThread == Thread.currentThread()) {
25             count++;
26             return true;
27         }
28         return false;
29     }
30
31     public synchronized void freeMutexFlag() {
32         if (currentThread == Thread.currentThread()) {
33             count--;
34         }
35         if (count == 0) {
36             currentThread = null;
37             notify();
38         }
39     }
40 }

为了编写方便我把判断获取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

时间: 2024-11-09 20:32:58

自制Java中的Mutex类的相关文章

java中的 FileWriter类 和 FileReader类

java中的 FileWriter类 和 FileReader类的一些基本用法 1,FileWriter类(字符输出流类) 构造方法:FileWriter fw = new FileWriter(String fileName);//创建字符输出流类对象和已存在的文件相关联.文件不存在的话,并创建. 如:FileWriter fw = new FileWriter("C:\\demo.txt"); FileWriter fw = new FileWriter(String fileNa

使用myeclipse开发java,解决java中继承JFrame类出现The type JFrame is not accessible due to restriction的问题

在java中创建窗体,导入了java中的JFrame类,之后会出现错误: Access restriction: The type QName is not accessible due to restriction on required library D:\myeclipse professer2014 可以解决的办法为: Project—>Properties—>选中Java Build Path—>选择Libraries,出现下面界面: 选中窗口中原有的JRE库,点击Remov

Java中的嵌套类和内部类

以前看<Java编程思想>的时候,看到过嵌套类跟内部类的区别,不过后来就把它们的概念给忘了吧.昨天在看<数据结构与算法分析(Java语言版)>的时候,又遇到了这个概念,当时就很大的疑惑:嵌套类跟内部类有什么区别?只有是否有关键字static的区别吗? 所以今天找了个时间查了一下两者的详细区别,总结在这篇博客中,既方便自己的复习和学习,也启示他人吧. 1,概念: 定义在一个类内部的类,叫作"嵌套类".嵌套类分为两种:static的和非static的.后者又有一个专

java中的File类

File类 java中的File类其实和文件并没有多大关系,它更像一个对文件路径描述的类.它即可以代表某个路径下的特定文件,也可以用来表示该路径的下的所有文件,所以我们不要被它的表象所迷惑.对文件的真正操作,还得需要I/O流的实现. 1.目录列表 如果我们想查看某个目录下有那些文件和目录,我们可以使用File中提供的list方式来查看,这很像linux下的ls命令. 查看E:/html文件夹下所有的php文件,执行的时候输入的参数为正则表达式 1 package com.dy.xidian; 2

java 中的String类

String a = "aaa"; 用这种方式的时候java首先在内存中寻找"aaa"字符串,如果有,就把aaa的地址给它 如果没有则创建 String a = new String("aaa"); 是不管内存中有没有"aaa" 都开辟一块新内存保存它 可以用以下方法验证下 String a = "aaa"; String b = "aaa"; String c = new String

Java中的Object类

关于Object类的equals()方法的特点: 1) 自反性:对于非空引用x来说,x.equals(x)一定返回true: 2) 对称性:对于非空引用x和y来说,如果x.equals(y)返回true,那么y.equals(x)一定返回true: 3) 传递性:对于非空引用x.y和z来说,如果x.equals(y)返回true,并且y.equals(z)返回true,那么x.equals(z)一定返回true: 4) 一致性:对于非空引用x和y来说,如果x.equals(y)返回true,那么

【Java】Java中的Collections类——Java中升级版的数据结构【转】

一般来说课本上的数据结构包括数组.单链表.堆栈.树.图.我这里所指的数据结构,是一个怎么表示一个对象的问题,有时候,单单一个变量声明不堪大用,比如int,String,double甚至一维数组.二维数组无法完全表达你要表达的东西,而定义一个类Class有太过麻烦,这时候,你可以考虑一下用Java中的Collections类.使用Collections类,必须在文件头声明import java.util.*;   一.动态.有序.可变大小的一维数组Vector与ArrayList Collecti

23 在java中使用groovy类

1       在java中使用groovy类 1.1  直接调用groovy类 在java中调用Groovy类,需要增加Groovy运行时到java的classpath中. pom.xml <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>2.4.5</version> <

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

Object类 java.lang.Object java.lang包在使用的时候无需显示导入,编译时由编译器自动导入. Object类是类层次结构的根,Java中所有的类从根本上都继承自这个类. Object类是Java中唯一没有父类的类. 其他所有的类,包括标准容器类,比如数组,都继承了Object类中的方法. Object类中的方法 构造方法:public Object() 文档中的类概览: Java中的每个类都具有定义在Object类中的这些方法. protected Object cl