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.
因为有了全局同步的时间,所以任何相关事件都可以全排序,所以可以线性化。