Art of Multiprocessor Programming 答案 ch13

158.

public class StripedHashSet
   
   
    
     extends BaseHashSet
    
    
     
     
{
    final ReadWriteLock[] locks;
    //...
    
    public final void acquire(T x)
    {
        locks[x.hashCode() % locks.length].readLock().lock();
    }
    
    public void release(T x)
    {
        locks[x.hashCode() % locks.length].readLock().unlock();
    }
    
    public void resize()
    {
        for(Lock lock : locks)
        {
            lock.writeLock().lock();
        }
        
        //...
        
        for(Lock lock: locks)
        {
            lock.writeLock().unlock();
        }
    }
}

    
    
   
   

159.

因为bucket要为hashset提供shortcut,但是对list的remove和对bucket的值remove不能原子的实现,所以会有问题。

如果先从list中删除,再处理bucket指向,则通过bucket访问hashset的线程有可能得到已经被删除的节点;

如果先处理bucket指向,再处理list,则考虑这样的case:

bucket = a,  在list中 a-->b; 

线程A remove a,首先找到b,并认为b合法,应该有bucket=b;

线程B remove b,没有corner case, remove b结束; 

线程A 令bucket=b, 在list中remove a,结束。


160.

摊还分析。


161.

如果允许一个比较大的但是flexible的数据结构,可以用14章介绍的SkipList。

如果要求任意大小,因为resize只考虑增加不考虑减少,所以可以采用这样的二叉树:

 

package p161;

import java.util.BitSet;
import java.util.concurrent.atomic.AtomicReference;


//First bit of key(BitSet) set as 1 to calculate length of bitset
public class Node
   
   
    
    
{
	private final int key;
	private final BitSet bits;
	private AtomicReference
    
    
     
     
      
      > left;
	private AtomicReference
      
      
       
       
         > right; private AtomicReference 
        
          sentinal; private void init() { left = new AtomicReference 
          
          
            >(null); right = new AtomicReference 
            
            
              >(null); sentinal = new AtomicReference 
             
               (null); } private Node(int key, BitSet bits) { this.key = key; this.bits = bits; init(); } public Node() { this.key = 0; this.bits = new BitSet(1); this.bits.set(0, true); init(); } private Node 
              
                createNode(boolean rChild) { int bitLen = bits.length(); int newValue = rChild? 1: 0; BitSet newBits = new BitSet(bitLen + 1); int i = 0; for(; i < bitLen - 1; i ++) { newBits.set(i, bits.get(i)); } newBits.set(i, rChild); newBits.set(i + 1, true); int newKey = key | (newValue << (bitLen - 1)); return new Node 
               
                 (newKey, newBits); } public Node 
                
                  getChild(boolean isRight) { AtomicReference 
                  
                  
                    > child = isRight? right: left; if(child.get() != null) { return child.get(); }else { Node 
                   
                     newChild = createNode(isRight); child.compareAndSet(null, newChild); return child.get(); } } public static BitSet IntToBits(int key) { long MASK = Long.MAX_VALUE; int BITMASK = 1; int index = 0; //64bits enough for int BitSet bits = new BitSet(); while((key & MASK) != 0) { boolean keyBit = (key & BITMASK) == 0? false: true; bits.set(index, keyBit); MASK <<= 1; BITMASK <<= 1; index ++; } bits.set(index, true); return bits; } public static int BitsToInt(BitSet bits) { int key = 0; for(int i = 0; i < bits.length() - 1; i ++) { int bitV = bits.get(i)? 1: 0; key |= (bitV << i); } return key; } public Node 
                    
                      getLeft() { return getChild(false); } public Node 
                     
                       getRight() { return getChild(true); } public Node 
                      
                        getLeftChild() { return left.get(); } public Node 
                       
                         getRightChild() { return right.get(); } public int getKey() { return key; } public T getSentinal() { return sentinal.get(); } public void setSentinal(T x) { sentinal.set(x);; } public BitSet getKeySet() { return bits; } } package p161; import java.util.BitSet; public class LocklessBinaryTree 
                        
                          { private Node 
                         
                           root; public LocklessBinaryTree(T initV) { root = new Node 
                          
                            (); root.setSentinal(initV); } public Node 
                           
                             getRoot() { return root; } public Node 
                            
                              getNearestAncestor(BitSet key) { int len = key.length(); Node 
                             
                               node = root; Node 
                              
                                child = node; for(int i = 0; i < len - 1; i ++) { if(key.get(i)) { child = node.getRight(); }else { child = node.getLeft(); } //Make sure parent has sentinal set if(child == null || child.getSentinal() == null) { return node; }else { node = child; } } return node; } public Node 
                               
                                 getChild(Node 
                                
                                  parent, boolean isRight) { if(parent == null) { return null; } Node 
                                 
                                   node = parent.getChild(isRight); return node; } } 
                                  
                                 
                                
                               
                              
                             
                            
                           
                          
                         
                        
                       
                      
                     
                    
                   
                  
                 
                
               
              
             
            
           
          
         
       
      
      
     
     
    
    
   
   

package p161;


/*
 * LockFreeHashSet.java
 *
 * Created on December 30, 2005, 12:48 AM
 *
 * From "Multiprocessor Synchronization and Concurrent Data Structures",
 * by Maurice Herlihy and Nir Shavit.
 * Copyright 2006 Elsevier Inc. All rights reserved.
 */


//import ch13.Hash.src.hash.*;


import java.util.BitSet;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @param T item type
 * @author Maurice Herlihy
 */
public class LockFreeHashSet
    
    
     
      {
  
  protected LocklessBinaryTree
     
     
      
      
       
        > tree;
	
  protected AtomicInteger bucketSize;
  protected AtomicInteger setSize;
  private static final double THRESHOLD = 4.0;

  public LockFreeHashSet() 
  {
	BucketList
       
       
        
         list = new BucketList
        
        
          (); tree = new LocklessBinaryTree 
          
          
            >(list); bucketSize = new AtomicInteger(2); setSize = new AtomicInteger(0); } public boolean add(T x) { int myBucket = Math.abs(BucketList.hashCode(x) % bucketSize.get()); BucketList 
           
             b = getBucketList(myBucket); if (!b.add(x)) return false; int setSizeNow = setSize.getAndIncrement(); int bucketSizeNow = bucketSize.get(); if (setSizeNow / (double)bucketSizeNow > THRESHOLD) bucketSize.compareAndSet(bucketSizeNow, 2 * bucketSizeNow); return true; } public boolean remove(T x) { int myBucket = Math.abs(BucketList.hashCode(x) % bucketSize.get()); BucketList 
            
              b = getBucketList(myBucket); if (!b.remove(x)) { return false; // she's not there } return true; } public boolean contains(T x) { int myBucket = Math.abs(BucketList.hashCode(x) % bucketSize.get()); BucketList 
             
               b = getBucketList(myBucket); return b.contains(x); } private BucketList 
              
                getBucketList(int myBucket) { BitSet bits = Node.IntToBits(myBucket); Node 
                
                
                  > parent = tree.getNearestAncestor(bits); if(parent.getKey() == myBucket) { return parent.getSentinal(); } BitSet parentBits = parent.getKeySet(); int index = parentBits.length() - 1; Node 
                  
                  
                    > node = null; for(; index < (bits.length() - 1); index ++) { node = tree.getChild(parent, bits.get(index)); if(node.getSentinal() == null) { BucketList 
                   
                     b = parent.getSentinal().getSentinel(node.getKey()); if(b != null) //Is that possible? { node.setSentinal(b); } } parent = node; } return node.getSentinal(); } } 
                    
                   
                  
                 
                
               
              
             
            
           
          
        
       
       
      
      
     
     
    
    

162.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值