Как правильно заблокировать поток с помощью ReentrantLock или Mutex? - PullRequest
1 голос
/ 14 февраля 2020

У меня есть метод acyn c с обратным вызовом:

myAsyncMethod(params) {
    handleResult(it)
}

Мне нужно преобразовать его в метод syn c (блокировать и вернуть результат) следующим образом:

val result = mySyncMethod(params)
handleResult(result)

Я не могу повторно реализовать его другим способом, потому что этот метод предоставлен сторонней библиотекой.

Я пытаюсь использовать ReentrantLock:

fun mySyncMethod(params:Type) {
    Log.d("tag", "1")
    val result = null
    val mutex = ReentrantLock()
    myAsyncMethod(params) {
        Log.d("tag", "3")
        result = it
        mutex.unlock()
    }
    Log.d("tag", "2")
    mutex.lock()
    Log.d("tag", "4")
    return result
}

handleResult(mySyncMethod(params))

Я жду, что должен см. 1, 2, 3, 4. Но я получаю 1, 2, 4, 3 и ноль в handleResult. Я пытаюсь сделать то же самое с мьютексом, но с тем же результатом. Как заставить это работать?

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

Ответы [ 2 ]

1 голос
/ 19 февраля 2020

Я ожидаю, что увижу 1, 2, 3, 4.

Тогда вы неправильно поняли, для чего на самом деле ReentrantLock.

Если mySyncMethod можно вызывать из разных потоков, то после вызова mutex.lock() только один поток за раз может выполнить код, следующий за mutex.lock() - другие потоки, выполняющие этот метод, должны ждать. После вызова mutex.unlock() один из ожидающих потоков также выполнит код и так далее.

Итак, поток, владеющий mutex, заставляет другие потоки ждать, но его собственный поток не блокируется. myAsyncMethod начинает работать после того, как внешний метод уже завершен, и, следовательно, result по-прежнему null.

Мне нужно преобразовать его в метод syn c (блок и вернуть результат), как это:

В соответствии с вашими требованиями, вам нужно заблокировать текущий поток, пока задача asyn c не будет завершена. Чтобы достичь этого, вы можете использовать Семафор или CountDownLatch . Например, с Semaphore ваш метод может выглядеть следующим образом:

fun mySyncMethod(params:Type) {
    Log.d("tag", "1")
    val result = null
    val semaphore = Semaphore(0)
    myAsyncMethod(params) {
        Log.d("tag", "3")
        result = it
        semaphore.release()
    }
    Log.d("tag", "2")
    semaphore.acquireUninterruptibly()
    Log.d("tag", "4")
    return result
}
1 голос
/ 19 февраля 2020

Вот мой код первым. Я использовал поток вместо вашего метода для проверки себя. Метод

fun main() {
    val mutex = ReentrantLock(true)
    val asyncCondition = mutex.newCondition()
    mutex.lock()
    try
    {
        print(1)


        thread {
            mutex.lock()
            try
            {
                print(2)
            }
            finally
            {
                asyncCondition.signalAll()
                mutex.unlock()
            }
        }

        asyncCondition.await()
        print(3)
    }
    finally
    {
        mutex.unlock()
    }
}

Java ReentrnatLock.lock блокирует поток, когда он уже заблокирован в одном и том же потоке. Поскольку вы пытаетесь заблокировать поток asyn c из другого потока, ваш код не работает. Чтобы заблокировать или освободить другой поток, вы можете использовать Condition как мой код.

Причина, по которой я везде использую оператор try..finally, заключается в том, что если после блокировки потока произошло исключение, вы собираетесь встретить бесконечность l oop, поэтому вы должны быть осторожны с этим делом.

Вы можете увидеть эти ссылки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...