说Hand-over-hand lock: 通读Concurrent Programming in Java: Design Principles and Patterns (1)

网络是个好东西,想学什么想用什么,一搜就基本能找到, 有时由于输入的关键词不佳, 难找到合适的结果, 有时干脆就是没有相关的网页(或者是问题太简单), 这样的时候自已难免会多花时间琢磨, 这些琢磨的结果, 对其他朋友是有益的,博客这种一对多的媒介,很适用于这样的传播.
对于个人而言,开博, 有利监督自已把所学所悟分享出来, 把自己生活工作的片段分享出来, 或是"晒"出来. 这是第二次开博,第一次是在 Davies(这个Blogger最近不太更新哦)开发的BlogXP上, 坚持开了大概半年有余,却由于种种主观原因, 放弃了对它的维护. 这次看看自己能坚持多久.

  Concurrent Programming in Java™: Design Principles and Patterns 是本不错的书,其中不是教条式教你如何用线程,如何同步, 不是过多罗列具体的实现技巧, 而是从多线程的需求出发, 考虑实现1)分时计算2)提高运算速度这两种需求下应如何解决资源访问的问题. 今天看到一处说hand-over-hand lock的地方, 对于为什么使用这种lock不能理解, 为什么要hand-over-hand lock呢, 为什么不是single-hand lock, 又不是hand-over-hand-over-hand lock(同时lock三个对象), 而需要同时lock两个对象呢?  且先看书中的代码示例:
class  ListUsingMutex  {

 
static class Node {
  Object item;
  Node next;
  Mutex lock 
= new Mutex(); // each node keeps its own lock
  Node(Object x, Node n) { item = x; next = n; }
 }


 
protected Node head; // pointer to first node of list

 
//Use plain synchronization to protect head field.
 
// (We could instead use a Mutex here too but there is no
 
// reason to do so.)

 
protected synchronized Node getHead() return head; }

 
public synchronized void add(Object x) // simple prepend

  
// for simplicity here, do not allow null elements
  if (x == nullthrow new IllegalArgumentException();

  
// The use of synchronized here protects only head field.
  
// The method does not need to wait out other traversers
  
// that have already made it past head node.

  head 
= new Node(x, head);
 }

 
boolean search(Object x) throws InterruptedException {
  Node p 
= getHead();

  
if (p == null || x == nullreturn false;

  p.lock.acquire();  
// Prime loop by acquiring first lock.

  
// If above acquire fails due to interrupt, the method will
  
//   throw InterruptedException now, so there is no need for
  
//   further cleanup.

  
for (;;) {
   Node nextp 
= null;
   
boolean found;

   
try {
     found 
= x.equals(p.item);
     
if (!found) {
       nextp 
= p.next;
       
if (nextp != null{
         
try {      // Acquire next lock
                    
//   while still holding current
           nextp.lock.acquire();
         }

         
catch (InterruptedException ie) {
          
throw ie;    // Note that finally clause will
                       
//   execute before the throw
         }

       }

     }

   }

   
finally {     // release old lock regardless of outcome
    p.lock.release();
   }


   
if (found)
     
return true;
   
else if (nextp == null)
     
return false;
   
else
     p 
= nextp;
  }

 }


 
// ...  other similar traversal and update methods ...
}


这个例子是讲链表的, 为什么要一下持有两个lock呢? 我们这样来想: lock是为了避免资源访问冲突的, 这种实现允许多线程访问链表中的单个元素(而不是将链表整个当成一个资源lock起来), 这样就可能有其它的线程来同时访问一个结点,可以在遍历的过程中不用保持链表与遍历开始时相同.但为什么不只用一个lock呢, 如果线程A得到一个结点的lock后取得它的next()(nextp = p.next())结点,接着就释放这个lock. 这时,另一线程可能将nextp删除, 而这里的遍历就会出问题,因为nextp已经不在链表中了.
    更简单的说, 我们要明确共享资源的目的, 是要保证一次遍历过程中, 链表与开始遍历时的链表相同, 或是要保证链表遍历过程中的当前结点是此刻链表中的一个结点. 这里我们选择后者, 就需要两个lock.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值