Работал ли с ReadWriteLock

Ответ

Да, работал. ReadWriteLock полезен, когда есть частые операции чтения и редкие — записи. Он позволяет нескольким потокам читать данные одновременно, но блокирует всех читателей и писателей при записи.

Пример:

val lock = ReentrantReadWriteLock()

fun readData() {
    lock.readLock().lock()
    try {
        // чтение данных
    } finally {
        lock.readLock().unlock()
    }
}

fun writeData() {
    lock.writeLock().lock()
    try {
        // запись данных
    } finally {
        lock.writeLock().unlock()
    }
}

Нюансы:

  • Может привести к голоданию писателей, если чтение происходит постоянно.
  • Не поддерживает обновление блокировки (read → write без отпускания).
  • Альтернатива — StampedLock с оптимистичным чтением.

Ответ 18+ 🔞

Э, слушай, да, работал с этой штукой, ReadWriteLock. Вещь, в принципе, годная, если у тебя схема типичная: данные все читают дохуя раз, а пишут в них редко — как будто последний пряник со стола пытаются урвать.

Представь себе библиотеку, ёпта. Народ (потоки-читатели) может заходить пачками, брать книжки, листать — всем хватает места. Но как только приходит библиотекарь (поток-писатель), чтобы на полку новую партию поставить, он вешает табличку «ИДИТЕ НАХУЙ, ПЕРЕРЫВ», всех выгоняет, делает свои дела, а потом снова всех пускает. Примерно так это и работает.

Вот, смотри, как это в коде выглядит, простейший случай:

val lock = ReentrantReadWriteLock()

fun readData() {
    lock.readLock().lock()
    try {
        // чтение данных
    } finally {
        lock.readLock().unlock()
    }
}

fun writeData() {
    lock.writeLock().lock()
    try {
        // запись данных
    } finally {
        lock.writeLock().unlock()
    }
}

Выглядит вроде логично, да? Но тут, бля, есть подводные камни, о которых голова заболеть может.

Нюансы, на которые надо глаза пялить:

  • Голодание писателей. Это главная беда. Если у тебя читатели ломятся непрерывным потоком — как метро в час пик, — то бедный писатель может ждать своей очереди до второго пришествия. Сидит такой поток, держит в руках свежие данные, а войти не может, потому что читательский замок никогда полностью не отпускается. Картина маслом: обновление никогда не применится. Пиздец, а не ситуация.

  • Нельзя апгрейднуть блокировку. Вот представим: вошёл ты как читатель, посмотрел данные и понял — «ой, а тут надо чутка подправить». Так вот, хуй тебе! Нельзя просто так взять и превратить readLock в writeLock. Придётся сначала читательский отпустить, а потом уже писательский брать. А в этот момент между отпусканием и захватом состояние данных могло уже поменяться другим писателем. Получается race condition, волнение ебать. Нужно перепроверять условия — геморрой.

  • Есть альтернатива — StampedLock. Эта штука похитрее будет. У неё есть так называемое «оптимистичное чтение». Ты как бы читаешь данные безо всякого замка, а потом проверяешь, а не пришёл ли пока кто-нибудь и не пописал ли в них. Если нет — красота, работа сделана без лишних блокировок. Если да — тогда уже берёшь полноценную блокировку и перечитываешь. Как лотерея, но часто выигрышная. Только API у него чуть более мозговыносящее.

Короче, инструмент рабочий, но ты его вдумчиво применяй. Если пишешь раз в год, а читают каждую миллисекунду — то самое оно. Если же запись тоже часто нужна, то тут уже надо думать про другие механизмы, а то получишь тормоза и головную боль.