Я не знаю, правильно ли я понял ваш вопрос, поскольку вы говорите, что когда вы блокируете поддерево для записи, вся структура блокируется.
Таким образом, простое решение состоит в том, чтобы иметь одну блокировку RW для всей структуры.
Кстати, java.util.concurrent.atomic
не поможет вам больше, чем дерево замков RW.
Если вы хотите иметь возможность независимой блокировки братьев и сестер, вы можете воспользоваться вторым решением (деревом замков, в котором каждый узел имеет ссылку на своего родителя).
Блокировка узла будет блокировать его с помощью блокировки записи и блокировать каждого родителя с помощью блокировки чтения.
Родитель не может быть заблокирован, пока дочерний объект, потому что вы не можете получить его блокировку записи, так как блокировка дочернего элемента уже получила блокировку чтения.
Блокировка дочернего элемента разрешена только в том случае, если ни один другой поток не заблокировал запись ни одного из родителей.
Замок, описанный выше, является эксклюзивным замком.
(другое имя для блокировок чтения-записи - блокировки с общим доступом)
Чтобы добавить общие блокировки, каждому узлу также необходимо атомное целое число, указывающее:
если оно положительное, число косвенных заблокированных от записи дочерних элементов; если он отрицателен, сколько раз узел был заблокирован для чтения.
Кроме того, узел и его родители будут заблокированы для чтения, чтобы избежать получения новых блокировок записи для родителей.
Псевдокод:
Node {
// fields
parent: Node
lock: RWLock
count: AtomicInteger
}
public boolean trylocktree(node: Node, exclusive: boolean) {
if (exclusive) {
return trylocktree_ex(node, true);
} else {
return trylocktree_sh(node);
}
}
private boolean switch_count(i: AtomicInteger, diff: int) {
// adds diff to i if the sign of i is the same as the sign of diff
while (true) {
int v = i.get();
if (diff > 0 ? v < 0 : v > 0)
return false;
if (i.compareAndSet(v, v + diff))
return true;
}
}
private boolean trylocktree_ex(node: Node, writing: boolean) {
// check if a node is read-locked
if (!switch_count(node.count, 1))
return false;
// lock using the lock type passed as an arg
if (!node.lock(writing).trylock()) {
node.count--;
return false;
}
// read-lock every parent
if (!trylocktree_ex(node.parent, false)) {
node.count--
node.lock(writing).unlock();
return false;
}
return true;
}
private boolean trylocktree_sh(node: Node) {
// mark as shared-locked subtree
if (!switch_count(node.count, -1))
return false;
// get shared-lock on parents
if (!readlock_recursively(node)) {
node.count++;
return false;
}
return true;
}
private boolean readlock_recursively(node: Node) {
if (!node.lock(false).trylock())
return false;
if (!readlock_recursively(node.parent)) {
node.lock(false).unlock();
return false;
}
return true;
}
Если какая-либо блокировка не может быть получена, то вы разблокируете то, что заблокировали, и повторите попытку позже (для этого можно использовать глобальную переменную условия, тайм-аут и т. Д.).
РЕДАКТИРОВАТЬ: добавлен код для блокировки чтения / записи дерева