zoukankan      html  css  js  c++  java
  • 自制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用这个类写了一个函数funA(get到Mutex未释放),B用这个类写了一个函数funB(get到Mutex未释放),C调用了funA,funB,用在一个线程中了。则这个线程运行到funA时得到了Mutex,运行到funB时再去申请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

  • 相关阅读:
    hdu 2881 Jack's struggle(DP)
    [置顶] DataGridView控件---绑定数据方法
    Computational Geometry Template_Polygon
    Max retries exceeded with url
    Linux /proc 的意义
    [置顶] 生成树协议介绍
    StringBuffer与StringBuilder的异同
    linux 下Eclipse for C/C++的不常见设置
    [Elasticsearch] 分布式搜索
    oracle递归函数
  • 原文地址:https://www.cnblogs.com/chaiwentao/p/4680836.html
Copyright © 2011-2022 走看看