ReentrantLock загадочным образом разблокируется в том же потоке, даже когда другие потоки не обращаются к нему - PullRequest
3 голосов
/ 20 марта 2019

У меня есть некоторый код, который, я думаю, будет очень простым:

public int internalWrite(byte[] data, int offset, int size) throws InterruptedException {
    lock.lockInterruptibly();
    try {
        if (state == State.RELEASED) throw new TrackReleasedException();
        return track.write(data, offset, size, AudioTrack.WRITE_NON_BLOCKING);
    } finally {
        if (!lock.isHeldByCurrentThread()) {
            Log.e("phonographnative", "internalWrite() lock is not held by current thread! " + Thread.currentThread());
        } else lock.unlock();
    }
}

lock - это fair ReentrantLock, но проблема также возникает с не-1006 *.track - Android AudioTrack;его write метод в основном нативный код (но не имеет ничего общего с многопоточностью).В любом случае у него нет доступа к lock.Исключение практически никогда не применяется на практике (и никогда при расследовании такого поведения).Что происходит, так это то, что очень воспроизводимо (подробнее об этом позже) блокировка будет таинственным образом разблокирована в том же потоке, что приведет к появлению сообщения журнала.Раньше, когда у меня не было этой проверки, ожидалось, что IllegalMonitorStateException будет выброшен.После того, как это произошло пару раз, в самом коде блокировки будет java.lang.AssertionError: Attempt to repark.Некоторые примерные выходные данные журнала:

2019-03-20 12:20:37.428 8097-8181/com.kabouzeid.gramophone.debug E/phonographnative: internalWrite() lock is not held by current thread! Thread[phonographnative-decoding-65308.0,5,main]
2019-03-20 12:20:37.428 8097-8184/com.kabouzeid.gramophone.debug E/phonographnative: internalWrite() lock is not held by current thread! Thread[phonographnative-decoding-65308.0,5,main]
2019-03-20 12:20:37.428 8097-8181/com.kabouzeid.gramophone.debug E/phonographnative: internalWrite() lock is not held by current thread! Thread[phonographnative-decoding-65308.0,5,main]
2019-03-20 12:20:37.428 8097-8184/com.kabouzeid.gramophone.debug E/phonographnative: internalWrite() lock is not held by current thread! Thread[phonographnative-decoding-65308.0,5,main]
2019-03-20 12:20:37.430 8097-8184/com.kabouzeid.gramophone.debug E/AndroidRuntime: FATAL EXCEPTION: phonographnative-decoding-65308.0
    Process: com.kabouzeid.gramophone.debug, PID: 8097
    java.lang.AssertionError: Attempt to repark
        at java.lang.Thread.parkFor$(Thread.java:2143)
        at sun.misc.Unsafe.park(Unsafe.java:325)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:161)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:840)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1220)
        at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:312)
        at com.kabouzeid.gramophone.service.ffmpeg.AudioContext.internalWrite(AudioContext.java:197)
        at com.kabouzeid.gramophone.service.ffmpeg.AudioContext.write(AudioContext.java:177)
        at com.kabouzeid.gramophone.service.ffmpeg.FFmpegPlayer.decodeAndPlayAudio(Native Method)
        at com.kabouzeid.gramophone.service.ffmpeg.FFmpegPlayer.lambda$new$0(FFmpegPlayer.java:72)
        at com.kabouzeid.gramophone.service.ffmpeg.-$$Lambda$FFmpegPlayer$MKAlsDZBJzprKYoChfgA-0JlIi8.run(lambda)
        at java.lang.Thread.run(Thread.java:761)

Это происходит, даже если никакие другие потоки не пытаются запустить этот код, и даже если я закомментирую все другие попытки заблокировать / разблокировать эту блокировку (другими потоками, в другомразделы кода).Эта проблема редко возникает периодически, но надежно, когда я пытаюсь приостановить AudioTrack, в который выполняется запись.Это не происходит при первоначальной записи в него или при выполнении чего-либо еще (например, при запуске воспроизведения с нуля).Эта бездействие происходит в совершенно другом потоке, и я не смог определить причинную связь между этими двумя вещами.Это может быть просто случайное сумасшествие планировщика.

Метод internalWrite вызывается очень часто, порядка тысяч раз в секунду.У меня есть ощущение, что это просто ошибка в реализации Android ReentrantLock, учитывая, что проверяемое утверждение полностью находится в коде JVM.(Что означает «Попытка перепарковки»?) Но я не могу исключить, что пропустил некоторые другие детали в своем собственном коде, и я был бы признателен за любые мысли по этому поводу!

Полный код можетможно найти здесь .Я также отследил соответствующие разделы в коде Android: AudioTrack # write , native_write_byte (метод вызывается по-другому), writeToTrack , AudioTrack-> запись .Однако они никак не помогли мне выяснить эту ошибку.

...