哎哟~ 不错哦~'s Blog

Happy coding

Latch 的相关笔记

背景介绍 :

         在java多线程中 , 当用到相关的Worker Thread模式的时候,启动多的Worker 线程执行方法doWork(). 伪代码如下:

         for (int i = 0; i < N; ++i)
               new Thread(new Worker()).start();

               doSomething();

         这个时候,这些后台线程将会立刻与soSomething()方法并行执行执行相关的run()方法. 现在需要一个解决方案,目的是让这些工作者线程在执行了doSomething()以后才开始执行相关的线程run()方法. 解决的方案有多种,仁者见仁,下面介绍的是用Latch的方式来完成线程的调度.

准备环境 : 

            下载EDU.oswego.cs.dl.util.concurrent相关的jar包以及源代码;

 

前提介绍

            使用Latch的时候,可以先看一下相关的源代码. Latch的源代码并不多,实现了Sync接口,方法有三个,

并且是线程安全的. 下面逐一介绍 :

           (1)acquire()方法: 此方法中,如果latched_变量(Latch的实例变量,boolean)为false, 就wait();这里多说一句,也算给自己提个醒, wait()会释放掉this锁并进入this的的等待区,等待notify()或者notifyAll()使之"醒来",但是醒来以后要重新获取this锁,并不是马上就能够执行的.

           (2)attempt(long msecs):这个方法很有趣,仔细看源代码,这个方法并不是先睡上个msecs长的时间,而是将会首先判断是否latched_变量是否为ture,是就return ture表示可以进入临界区.不是的话将会进入for(;;)无限循环, 在循环中,首先wait(msecs). 特别注意,wait(msecs)并不是就一定要等待msecs时间,JDK 对此方法作出的解释是 :

          

此方法导致当前线程(称之为 T)将其自身放置在对象的等待集中,然后放弃此对象上的所有同步要求。出于线程调度目的,线程 T 被禁用,且处于休眠状态,直到发生以下四种情况之一:

  • 其他某个线程调用此对象的 notify 方法,并且线程 T 碰巧被任选为被唤醒的线程。
  • 其他某个线程调用此对象的 notifyAll 方法。
  • 其他某个线程中断线程 T
  • 已经到达指定的实际时间。但是,如果 timeout 为零,则不考虑实际时间,该线程将一直等待,直到获得通知。

然后,从对象的等待集中删除线程 T,并重新进行线程调度。然后,该线程以常规方式与其他线程竞争,以获得在该对象上同步的权利;一旦获得对该对象的控制权,该对象上的所有其同步声明都将被还原到以前的状态 - 这就是调用 wait 方法时的情况。然后,线程 Twait 方法的调用中返回。所以,从 wait 方法返回时,该对象和线程 T 的同步状态与调用 wait 方法时的情况完全相同。

  明白了这一点,也许就不难理解为什么wait(smsecs)时间后还要用 :waitTime = msecs - (System.currentTimeMillis() - start);这样的语句判断是否超时.

          (3) release() :这个方法将标志位latched_设置为ture,并进行notify操作.

运行机理 :

         想想一下,出事状况下(Fatch中的标志位_latched初始值为false)当多个线程调用acquire()的时候,因为标志位为false,那么将集体进入等待区. 当外界调用此Fatch对象的release()方法时候,由于notifyAll()并且将标志位设置为ture的原因,等待区中的线程集体排着队来“通过检查门口”并进行后续操作. 这样就能达到问题需要解决的目标;

       

        下面是在Latch类中的实例代码,我将之粘贴出来以保证Blog的完整性 :

 

      class Worker implements Runnable {
 *   private final Latch startSignal;
 *   Worker(Latch l) { startSignal = l; }
 *    public void run() {
 *      startSignal.acquire();
 *      doWork();
 *   }
 *   void doWork() { ... }
 * }
 *
 * class Driver { // ...
 *   void main() {
 *     Latch go = new Latch();
 *     for (int i = 0; i < N; ++i) // make threads
 *       new Thread(new Worker(go)).start();
 *     doSomethingElse();         // don't let run yet
 *     go.release();              // let all threads proceed
 *   }
 * }

 

 

 

         

        

      

        

        

Rational Rose 2003 Revers

环境 :  操作系统平台:

        工具 : Rational Rose 2003

        编程平台 : java/jee 

       

书写背景 :

     在我们分析项目源项目,又或者你拿到一本好书,想测试书中的代码的时候. 一两个类也许是很容易理清楚其中的脉络的,但是,正如面对数据一样, 类的数目一多起来, 往往要先从类图来分析会更加容易一些. 并且还能结合设计模式或者数据结构来从结构上先理解代码是怎么一回事情.  这个时候, 一般用MyEclipse 的方向工程或者Rose ,Together等工具能够利用反向工程由具体的代生成出类图.

反向目的:

     1 得到类图更容易分析出复杂代码后面的结构

     2 利用生成的类图来学习Rose中UML的一些标准表示,一些细节(例如:static,final字段和Abstract等等一般容易忽略的表示,使得开发更规范和交流起来更加清晰)

反向步骤 :

        1 选取Rose相关的模板(如下图):

        

        2  tools---->java/j2ee-->Revers Engineer...,如下图:

      

        3 在选择之后弹出的文件框中(如图):

        

      左边上角的E:\JAVA\JDK\TOOLS.JAR是你自己的JDK环境设置,Rose会自动加载这个JDK jar包是因为建立了相关的j2se模板.  然后:

       (1) 将你的源代码用到的除了标准JDK的jar以外的项目依赖jar包,比如我的项目就依赖了concurrent.jar 这个并发第三方包,对应的MyEclipse的Build Path如图 :

         

       在Rose 弹出的窗口中点击"EDIT CLASSPATH", 选中图标中的New (Insert) :

     

     点击Insert以后出现下面的文件类型选择框,因为此步骤是引入jar包,选择Jar/Zip方式:

      

    选中的的第三方依赖包即可完成. 完成以后如图 :

 

  (2) 选择你的源代码目录,重复上面的(1)步骤,只不过选中的类型应该是Directory,完成以后,如下图,在右边会出现逆源代码目录中的.java文件

 

  (3)选中上图中的.java文件,点击“Add”,java文件将会出现在最下面的框中,这个框里面的java文件及是需要进行方向的文件,如下图:

  

 点击 Reverse 即可完成方向工程.

 完成之后,在你的UML项目中的"Logic view" 和 "Component View"中会出现相关的方向文件:

 

最后,需要建立一个Class Diagram 来把转换过来的类和接口呈现出来即可.

 

参考链接 :

          http://hi.baidu.com/suofang/blog/item/b4190de9846ea53eb80e2d1e.html