中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档 | 网通镜像
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 编程语言 > Java > java高级编程
关于多线程同步的初步教程--Metux的设计及使用
作者:未知 时间:2005-07-24 21:15 出处:JR 责编:chinaitpower
              摘要:关于多线程同步的初步教程--Metux的设计及使用
    Mutex是互斥体,广泛地应用在多线程编程中。本文以广为流程的Doug Lea的concurrent工具包的Mutex实现为例,进行一点探讨。在Doug Lea的concurrent工具包中,Mutex实现了Sync接口,该接口是concurrent工具包中所有锁(lock)、门(gate)和条件变量(condition)的公共接口,Sync的实现类主要有:Mutex、Semaphore及其子类、Latch、CountDown、ReentrantLock等。这也体现了面向抽象编程的思想,使我们可以在不改变代码或者改变少量代码的情况下,选择使用Sync的不同实现。下面是Sync接口的定义:

  1. public interface Sync {
  2.   public void acquire() throws InterruptedException//获取许可
  3.   public boolean attempt(long msecs) throws InterruptedException//尝试获取许可
  4.   public void release(); //释放许可
  5. }

通过使用Sync可以替代Java synchronized关键字,并提供更加灵活的同步控制。当然,并不是说concurrent工具包是和Java synchronized独立的技术,其实concurrent工具包也是在synchronized的基础上搭建的,从下面对Mutex源码的解析即可以看到这一点。synchronized关键字仅在方法内或者代码块内有效,而使用Sync却可以跨越方法甚至通过在对象之间传递,跨越对象进行同步。这是Sync及concurrent工具包比直接使用synchronized更加强大的地方。
    注意Sync中的acquire()和attempt()都会抛出InterruptedException,所以使用Sync及其子类时,调用这些方法一定要捕获InterruptedException。而release()方法并不会抛出InterruptedException,这是因为在acquire()和attempt()方法中可能会调用wait()等待其它线程释放锁。而release()在实现上进行了简化,直接释放锁,不管是否真的持有。所以,你可以对一个并没有acquire()的线程调用release()这也不会有什么问题。而由于release()不会抛出InterruptedException,所以我们可以在catch或finally子句中调用release()以保证获得的锁能够被正确释放。比如:

  1. class X {
  2.    Sync gate;
  3.    // ...
  4.    public void m() { 
  5.      try {
  6.        gate.acquire();  // block until condition holds
  7.        try {
  8.          // ... method body
  9.        }
  10.        finally {
  11.          gate.release();
  12.        }
  13.      }
  14.      catch (InterruptedException ex) {
  15.        // ... evasive action
  16.      }
  17.    }
  18. }



Mutex是一个非重入的互斥锁。Mutex广泛地用在需要跨越方法的before/after类型的同步环境中。下面是Doug Lea的concurrent工具包中的Mutex的实现。

  1. public class Mutex implements Sync  {
  2.   /** The lock status **/
  3.   protected boolean inuse_ = false;
  4.   public void acquire() throws InterruptedException {
  5.     if (Thread.interrupted()) throw new InterruptedException(); //(1)
  6.     synchronized(this) {
  7.       try {
  8.         while (inuse_) wait(); 
  9.         inuse_ = true;
  10.       }
  11.       catch (InterruptedException ex) { //(2)
  12.         notify();
  13.         throw ex;
  14.       }
  15.     }
  16.   }
  17.   public synchronized void release()  {
  18.     inuse_ = false;
  19.     notify(); 
  20.   }
  21.   public boolean attempt(long msecs) throws InterruptedException {
  22.     if (Thread.interrupted()) throw new InterruptedException();
  23.     synchronized(this) {
  24.       if (!inuse_) {
  25.         inuse_ = true;
  26.         return true;
  27.       }
  28.       else if (msecs <= 0)
  29.         return false;
  30.       else {
  31.         long waitTime = msecs;
  32.         long start = System.currentTimeMillis();
  33.         try {
  34.           for (;;) { 
  35.             wait(waitTime);
  36.             if (!inuse_) {
  37.               inuse_ = true;
  38.               return true;
  39.             }
  40.             else {
  41.               waitTime = msecs - (System.currentTimeMillis() - start);
  42.               if (waitTime <= 0) // (3)
  43.                 return false;
  44.             }
  45.           }
  46.         }
  47.         catch (InterruptedException ex) {
  48.           notify();
  49.           throw ex;
  50.         }
  51.       }
  52.     }  
  53.   }
  54. }


    为什么要在acquire()和attempt(0方法的开始都要检查当前线程的中断标志呢?这是为了在当前线程已经被打断时,可以立即返回,而不会仍然在锁标志上等待。调用一个线程的interrupt()方法根据当前线程所处的状态,可能产生两种不同的结果:当线程在运行过程中被打断,则设置当前线程的中断标志为true;如果当前线程阻塞于wait()、sleep()、join(),则当前线程的中断标志被清空,同时抛出InterruptedException。所以在上面代码的位置(2)也捕获了InterruptedException,然后再次抛出InterruptedException。
    release()方法简单地重置inuse_标志,并通知其它线程。
    attempt()方法是利用Java的Object.wait(long)进行计时的,由于Object.wait(long)不是一个精确的时钟,所以attempt(long)方法也是一个粗略的计时。注意代码中位置(3),在超时时返回。
    Mutex是Sync的一个基本实现,除了实现了Sync接口中的方法外,并没有添加新的方法。所以,Mutex的使用和Sync的完全一样。在concurrent包的API中Doug给出了一个精细锁定的List的实现示例,我们这儿也给出,作为对Mutex和Sync使用的一个例子:

  1. class Node { 
  2.    Object item; 
  3.    Node next; 
  4.    Mutex lock = new Mutex(); // 每一个节点都持有一个锁
  5.    Node(Object x, Node n) { item = x; next = n; }
  6.  }
  7.  class List {
  8.     protected Node head; // 指向列表的头
  9.     // 使用Java的synchronized保护head域
  10.     //  (我们当然可以使用Mutex,但是这儿似乎没有这样做的必要
  11.     protected synchronized Node getHead() { return head; }
  12.     boolean search(Object x) throws InterruptedException {
  13.       Node p = getHead();
  14.       if (p == nullreturn false;
  15.       //  (这儿可以更加紧凑,但是为了演示的清楚,各种情况都分别进行处理)
  16.       p.lock.acquire();                  // Prime loop by acquiring first lock.
  17.                                      //    (If the acquire fails due to
  18.                                      //    interrupt, the method will throw
  19.                                      //    InterruptedException now,
  20.                                      //    so there is no need for any
  21.                                      //    further cleanup.)
  22.       for (;;) {
  23.         if (x.equals(p.item)) {
  24.           p.lock.release();          // 释放当前节点的锁
  25.           return true;
  26.         }
  27.         else {
  28.           Node nextp = p.next;
  29.           if (nextp == null) {
  30.             p.lock.release();       // 释放最后持有的锁
  31.             return false;
  32.           }
  33.           else {
  34.             try {
  35.               nextp.lock.acquire(); // 在释放当前锁之前获取下一个节点的锁
  36.             }
  37.             catch (InterruptedException ex) {
  38.               p.lock.release();    // 如果获取失败,也释放当前的锁
  39.               throw ex;
  40.             }
  41.             p.lock.release();      // 释放上个节点的锁,现在已经持有新的锁了
  42.             p = nextp;
  43.           }
  44.         }
  45.       }
  46.     }
  47.     synchronized void add(Object x) { // 使用synchronized保护head域
  48.       head = new Node(x, head);
  49.     }
  50.     // ...  other similar traversal and update methods ...
  51.  }


关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有