3

私はJavaの並行パッケージを学んでいます。
CopyOnWriteArrayLis のソースを読んだ後、次の質問があります。

private boolean addIfAbsent(E e, Object[] snapshot) {
        final ReentrantLock lock = this.lock;
        // Here is my question.
        lock.lock();
        try {
            Object[] current = getArray();
            int len = current.length;
            if (snapshot != current) {
                // Optimize for lost race to another addXXX operation
                int common = Math.min(snapshot.length, len);
                for (int i = 0; i < common; i++)
                    if (current[i] != snapshot[i] && eq(e, current[i]))
                        return false;
                if (indexOf(e, current, common, len) >= 0)
                        return false;
            }
            Object[] newElements = Arrays.copyOf(current, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

私の質問は、なぜオプティマイズが必要なのですか?
もちろん、私は自分自身をグーグルで検索しました.答えは常に、他のスレッドが新しい要素を追加した可能性があるときにそれを正しくすることです.

しかし、 lock.lock()を説明する方法は? 1 つのスレッドがロックを取得した場合、他のスレッドはどのように新しい要素を追加できますか?

ばかげた質問かもしれませんが、私はそれについて本当に混乱しています。

4

1 に答える 1

2

おそらくご覧のとおり、スナップショットはこの方法で取得されます

public boolean addIfAbsent(E e) {
        Object[] snapshot = getArray();
        return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
            addIfAbsent(e, snapshot);
    }

最後に、質問に入れたメソッドを呼び出します。

そのため、スナップショットが作成されてから現在のスレッドによってロックがロックされるまでの間に配列の操作が行われた場合は、それらを正しく処理する必要があります。
このような操作がこれら 2 つの時点の間に発生する方法はさまざまです。たとえば、addIfAbsentメソッドを呼び出すスレッドがスケジューラによって中断されます。
リストが頻繁に書き込まれている場合、あまりありそうもない別の状況として、現在のスレッドがロックしようとしたときに実際に別のスレッドによってロックがロックされているため、別のスレッドが操作を完了するまで待機する必要があります (これはロック自体をロックする前に、リストに要素を追加した可能性があります)、ロックを解除します。

于 2020-03-27T22:01:44.253 に答える