Bidirectional Threadsafe Association in Java

What is a good way to implement filamentary bidirectional associations? Maybe a good library or code generator?

Here is an unsafe example:

class Foo {

    private Foo other;

    public Foo getOther() {
        return other;
    }

    public void setOther(Foo other) {
        this.setOtherSecretly(other);
        other.setotherSecretly(this);
    }

    void setOtherSecretly(Foo other) {
        if (this.other != null) this.other.other = null;
        this.other = other;
    }
}

My thread safety requirements:

  • No deadlocks
  • Final Consistency (When all threads stop modifying objects, a consistent state is ultimately achieved. That is, it is acceptable that it assert foo.getOther().getOther() == foofails when another thread executes setOtherat the same time.
  • Consistent behavior. If the thread executes setOther, and no other thread overrides the value, getOtherimmediately returns a new value for that thread.
  • . getOther, ( ).

:

  • , . .
  • . .
  • . 5 , 3 . .

16 , 5000 .

(, ), (, , ) .

+3
6

Google Guava : BiMap.

:

BiMap<Integer, String> bimap = Synchronized.biMap(HashBiMap.create(), someMutexObject);
bimap.put(1, "one");
bimap.put(2, "two");

bimap.get(1); // returns "one"
bimap.inverse().get("one") // returns 1

someMutexObject , synchronize on.

+2

, , . . ,

class Foo extends ReentrantLock {

    private static final AtomicInteger order = new AtomicInteger(0);

    final int id = order.incrementAndGet();

    private Foo other;

    public Foo getOther() {
        return other;
    }

    public void setOther(Foo other) {
        if (id > other.id) {
            other.lock();
            try {
                this.lock();
                try {

                    // assign here
                } finally {
                    this.unlock();
                }
            } finally {
                other.unlock();
            }
        } else if (id < other.id) {
            this.lock();
            try {
                other.lock();
                try {

                    // assign here
                } finally {
                    other.unlock();
                }
            } finally {
                this.unlock();
            }
        }
    }
}
+1

(other) (-). .

0

, . , , , "" .

class Foo {

    private static final Object MONITOR = new Object();
    private Foo other;

    public Foo getOther() {
        synchronized(MONITOR){
            return other;
        }
    }

    public void setOther(Foo other) {
        synchronized(MONITOR){
            this.setOtherSecretly(other);
            other.setotherSecretly(this);
        }
    }

    void setOtherSecretly(Foo other) {
        if (this.other != null) this.other.other = null;
        this.other = other;
    }
}
0

, , ! (!) , , . , - , , . .

, ! , ! Deuce STM, , . ...

, , , , Java AtomicReference. -, :

class Foo {

    private AtomicReference<Foo> oRef = new AtomicReference<Foo>;

    private static final AtomicInteger order = new AtomicInteger(0);
    private final int id = order.incrementAndGet();

    private static bool break(Foo x, Foo y) {
        if (x.id > y.id)
            return break(y, x);

        return x.oRef.compareAndSet(y, null) &&
               y.oRef.compareAndSet(x, null);
    }

    public void setOther(Foo f) {
        if (f != null && f.id > id) {
            f.setOther(this);
            return;
        }
        do {
            Foo other = oRef.get();
            if (other == f)
                break;

            if (other != null && !break(this, other))
                continue;

            if (f == null)
                break;

            Foo fother = f.oRef.get();
            if (fother != null && !break(f, fother))
                continue;

            if (!f.oRef.compareAndSet(null, this))
                continue;
            if (!oRef.compareAndSet(null, f)) {
                f.oRef.set(null);
                continue;
            }
        } while (false);
    }
}

:

  • Foos ( 4), , .
  • .
  • , x.oRef.compareAndSet(y, null).
  • f.oRef.compareAndSet(null, f) , break(). , oRef.compareAndSet(null, f) , . , f.oRef reset, .
0

Source: https://habr.com/ru/post/1793669/


All Articles