173. SimpleTree 是不可线性化但是静态一致的。
174. 思路是
如果不要求保存状态可重用,则可以在输出端连接H个开关,比如说,如果output=1已经有token经过了,则当前counter>H,返回H。
如果考虑可重用,则发现>H则再加入一个反令牌,<0则再加入一个令牌。一个问题是如何在decrement用反令牌实现的前提下用开关标记是否是超过H的。
因为衍射树是静态一致的,AtomicBoolean也是静态一致的,他们的组合也是静态一致的。
package p174;
public class Balancer {
Boolean toggle;
public Balancer()
{
toggle = true;
}
public synchronized int traverse(boolean token)
{
if(token)
{
try
{
if (toggle)
{
return 0;
} else
{
return 1;
}
} finally
{
toggle = !toggle;
}
}else
{
toggle = !toggle;
if(toggle)
{
return 0;
}else
{
return 1;
}
}
}
}
package p174;
public class DiffractingTree
{
Balancer root;
DiffractingTree[] child;
int size;
public DiffractingTree(int mySize)
{
size = mySize;
root = new Balancer();
if(size > 2)
{
child = new DiffractingTree[]
{
new DiffractingTree(size / 2),
new DiffractingTree(size / 2),
};
}
}
public int traverse(boolean token)
{
int half = root.traverse(token);
if(size > 2)
{
return (2 * (child[half].traverse(token)) + half);
}else
{
return half;
}
}
}
package p174;
import java.util.concurrent.atomic.AtomicBoolean;
public class Counter
{
private final int bound;
private DiffractingTree tree;
private AtomicBoolean flags[];
public Counter(int bound)
{
this.bound = bound;
tree = new DiffractingTree(bound);
flags = new AtomicBoolean[bound];
for(int i = 0; i < flags.length; i ++)
{
flags[i] = new AtomicBoolean(false);
}
}
public int boundedGetAndIncrement()
{
int tmpRc = tree.traverse(true);
if(flags[tmpRc].compareAndSet(false, true))
{
return tmpRc;
}else
{
tmpRc = tree.traverse(false);
flags[tmpRc].compareAndSet(true, false);
return bound;
}
}
public int boundedGetAndDecrement()
{
int tmpRc = tree.traverse(false);
if(flags[tmpRc].compareAndSet(true, false))
{
return tmpRc;
}else
{
tmpRc = tree.traverse(true);
flags[tmpRc].compareAndSet(false, true);
return 0;
}
}
public static void main(String[] args)
{
Counter counter = new Counter(4);
for(int i = 0; i < 2; i ++)
{
int rc = counter.boundedGetAndIncrement();
System.out.println("" + i + "---------> " + rc);
}
for(int i = 0; i < 9; i ++)
{
int rc = counter.boundedGetAndDecrement();
System.out.println("-" + i + "---------> " + rc);
}
}
}
175.
负数,非零,走到错误的叶子。
176. 看不懂题目。这个本来就是有界容量的。
177.
removeMin超过add,在内部节点中发现无路可走。
178.
179.
import java.util.ArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Heap with fine-grained locking and arbitrary priorities.
* @param T type manged by heap
* @author mph
*/
public class FineGrainedHeap
implements PQueue
{
private static int ROOT = 1;
private static int NO_ONE = -1;
private Lock heapLock;
int next;
// HeapNode
[] heap;
ArrayList
> heap; /** * Constructor * @param capacity maximum number of items heap can hold */ public FineGrainedHeap(int capacity) { heapLock = new ReentrantLock(); next = ROOT; heap = new ArrayList
>(capacity + 1); } /** * Add item to heap. * @param item Uninterpreted item. * @param priority item priority */ public void add(T item, int priority) { heapLock.lock(); int child = next++; if(heap.size() <= child) { HeapNode
childElem = new HeapNode
(); heap.add(childElem); } //It should be right as next ++, add new element are sequential as they were locked by helpLock. //And there is no removal operation from list. //Anyway, the get(child) can throw Exception when index and element really mismatched. heap.get(child).lock(); heapLock.unlock(); //... } //... }
临时创建对象的开销,尤其是在全局锁中创建对象的开销。
180.
好处在于如果没有这个特性,相邻的2个插入在时间上是相差最短的,而且最容易有相同的父节点,所以产生同步开销的机率最大。
以 reverseIncrement为例:
public int reversedIncrement()
{
//如果counter越界,则归零
if(count ++ == 0)
{
reverse = highBit = 1;
return reverse;
}
//取bit为除了最高位的第一位。即根结点下的第一层子树位。
int bit = highBit >> 1;
while(bit != 0)
{
//从高位开始异或,所以相邻的2个节点必然不在同一个子树上。
reverse ^= bit;
/*
* 因为reverse ^= bit,又(reverse & bit == 0)
* ==> 假设bit = 0100,则异或之前reverse = x0xx
* ==> 原来的reverse在左树上,则找到右子树上的对应节点,退出。
* ==> 如果原来的reverse在右树上,则异或后转到左子树
* ==> 且bit >>= 1,即到下一层子树继续这个过程,直到找到一个右子树上的点。
*
* ==> 以上图为例,count = 8对应的reverse为1000,为子树1的最左节点
* ==> count = 9时,因为8在左子树,找到子树1的右子树的对应节点为12
* ==> count = 10,第一轮找到对称节点为8,在左子树,
* ==> 下降一层,到子树2的右子树上找对应的节点,找到10
* ==> count = 11,找到1的右子树的对应节点14
* ==> count = 12,第一轮得到对应节点为10,在左子树,
* ==> 下降一层,在子树2上,得到对应节点为8,得知原节点在2的右子树上,
* ==> 下降一层,在子树4上,得到对应右节点为9
* ==> ...
* ==> count = 15,得到节点15
* ==> count = 16,
*/
if((reverse & bit) != 0)
{
break;
}
bit >>= 1;
}
/*
* count = 16,得到bit = 0,即叶子节点层已经没有空余节点了
* 将最高位左移一位,即树高加一层,并在新层上找next。
*/
if(bit == 0)
{
reverse = highBit << = 1;
}
return reverse;
}
181.
作者有给出
182.
不从头开始也是可以的,因为要求只是静态一致性。
package p182;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LazySkipListQueue
{
static final int MAX_LEVEL = 4;
static int randomSeed = (int)(System.currentTimeMillis()) | 0x0100;
private static int randomLevel() {
int x = randomSeed;
x ^= x << 13;
x ^= x >>> 17;
randomSeed = x ^= x << 5;
if ((x & 0x80000001) != 0) // test highest and lowest bits
return 0;
int level = 1;
while (((x >>>= 1) & 1) != 0) ++level;
return Math.min(level, MAX_LEVEL-1);
}
private static final class Node
{
final Lock lock = new ReentrantLock();
final T item;
final int priority;
final Node
[] next;
volatile boolean marked = false;
volatile boolean fullLinked = false;
private int topLevel;
@SuppressWarnings("unchecked")
public Node(int priority)
{
this.item = null;
this.priority = priority;
next = (Node
[])new Node[MAX_LEVEL + 1];
topLevel = MAX_LEVEL;
}
@SuppressWarnings("unchecked")
public Node(T x, int priority)
{
this.item = x;
this.priority = priority;
int height = randomLevel();
next = (Node
[])new Node[height + 1]; topLevel = height; } public void lock() { lock.lock(); } public void unlock() { lock.unlock(); } } final Node
head = new Node
(Integer.MIN_VALUE); final Node
tail = new Node
(Integer.MAX_VALUE); public LazySkipListQueue() { for(int i = 0; i < head.next.length; i ++) { head.next[i] = tail; } } int find(Node
node, Node
[] preds, Node
[] succs) { int lFound = -1; Node
pred = head; for(int level = MAX_LEVEL; level >= 0; level --) { Node
curr = pred.next[level]; while(node.priority > curr.priority) { pred = curr; curr = pred.next[level]; } if(lFound == -1 && node.priority == curr.priority) { lFound = level; } preds[level] = pred; succs[level] = curr; } return lFound; } @SuppressWarnings("unchecked") boolean add(Node
newNode) { int topLevel = randomLevel(); Node
[] preds = (Node
[]) new Node[MAX_LEVEL + 1]; Node
[] succs = (Node
[]) new Node[MAX_LEVEL + 1]; while(true) { int lFound = find(newNode, preds, succs); if(lFound != -1) { Node
nodeFound = succs[lFound]; if(!nodeFound.marked) { while(!nodeFound.fullLinked){} return false; } continue; } int highestLocked = -1; try { Node
pred, succ; boolean valid = true; for(int level = 0; valid && (level < topLevel); level ++) { pred = preds[level]; succ = succs[level]; pred.lock(); highestLocked = level; valid = !pred.marked && !succ.marked && pred.next[level] == succ; } if(!valid) { continue; } for(int level = 0; level <= topLevel; level ++) { newNode.next[level] = succs[level]; } for(int level = 0; level <= topLevel; level ++) { preds[level].next[level] = newNode; } newNode.fullLinked = true; return true; }finally { for(int level = 0; level <= highestLocked; level ++) { preds[level].unlock(); } } } } @SuppressWarnings("unchecked") private boolean remove(Node
victim) { boolean isMarked = false; Node
[] preds = (Node
[]) new Node[MAX_LEVEL + 1]; Node
[] succs = (Node
[]) new Node[MAX_LEVEL + 1]; int topLevel = victim.topLevel; while(true) { int lFound = find(victim, preds, succs); if(!(lFound != -1 && lFound == victim.topLevel && victim.marked)) { return true; } victim.lock(); int highestLocked = -1; try { Node
pred; boolean valid = true; for(int level = 0; valid && (level <= topLevel); level ++) { pred = preds[level]; pred.lock(); highestLocked = level; valid = !pred.marked && pred.next[level] == victim; } if(!valid) { continue; } for(int level = topLevel; level >= 0; level --) { preds[level].next[level] = victim.next[level]; } victim.unlock(); return true; }finally { for(int i = 0; i <= highestLocked; i ++) { preds[i].unlock(); } } } } public Node
findAndMarkMin() { Node
ret = null; Node
pred = null; Node
curr = null; while(true) { pred = head; curr = pred.next[0]; while(curr.marked && curr != tail) { pred = curr; curr = pred.next[0]; } if(curr == tail) { return null; }else { try { pred.lock(); curr.lock(); if(!curr.marked && !pred.marked && pred.next[0] == curr) { curr.marked = true; ret = curr; remove(ret); return ret; } }finally { pred.unlock(); curr.unlock(); } } } } }
183.
2个线程同时findAndRemoveMin,因为都是从head开始沿list[bottom]寻找,所以很有可能在head.next[0]上冲突。
184.
因为有了全局同步的时间,所以任何相关事件都可以全排序,所以可以线性化。