Object.wait()的非阻塞替代?

时间:2018-02-10 05:15:05

标签: multithreading kotlin coroutine

我有一个线程从本地服务器接收数据包:

// Shared object:
@Volatile lateinit var recentPacket: Packet
val recvMutex = Object()

// Thread code:
thread(isDaemon = true) {
    while (true) {
        val packet = readPacket()
        synchronized(recvMutex) {
            recentPacket = packet
            recvMutex.notifyAll()
        }
    }
}

我有多个其他线程等待数据包,每个线程都应该获得刚收到的相同数据包:

suspend fun receive() {
    return synchronized(recvMutex) {
        recvMutex.wait() // non-blocking alternative to this?
        recentPacket
    }
}

它可以工作,但Object.wait()会阻止该线程。有没有办法避免这种情况?

2 个答案:

答案 0 :(得分:1)

  

它可以工作,但Object.wait()会阻止该线程。有没有办法避免这种情况?

是的,但这意味着删除您现在使用的完整wait-notify惯用语并将其替换为Kotlin的原生BroadcastChannel。我还建议不要依赖默认的CommonPool协程调度程序。这对原型代码来说是一个很好的方便,但在生产环境中你应该使用一个由你控制的线程池。

以下是一个基本示例,其中包含两个接收器和五个数据包:

import kotlinx.coroutines.experimental.asCoroutineDispatcher
import kotlinx.coroutines.experimental.channels.BroadcastChannel
import kotlinx.coroutines.experimental.channels.SubscriptionReceiveChannel
import kotlinx.coroutines.experimental.delay
import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.runBlocking
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors

private val threadPool = Executors.newCachedThreadPool() as ExecutorService
val MyPool = threadPool.asCoroutineDispatcher()

fun main(args: Array<String>) {
    val packetChannel = BroadcastChannel<Packet>(1)
    (1..2).forEach {
        launch(MyPool) {
            receivePackets(it, packetChannel.openSubscription())
        }
    }
    runBlocking {
        (1..5).forEach {
            packetChannel.send(Packet(it))
            delay(100)
        }
    }
    threadPool.shutdown()
}

suspend fun receivePackets(index: Int, packetChannel: SubscriptionReceiveChannel<Packet>) {
    while (true) {
        println("Receiver $index got packet ${packetChannel.receive().value}")
    }
}

data class Packet(
        val value: Int
)

期待看到这样的输出:

Receiver 1 got packet 1
Receiver 2 got packet 1
Receiver 2 got packet 2
Receiver 1 got packet 2
Receiver 1 got packet 3
Receiver 2 got packet 3
Receiver 1 got packet 4
Receiver 2 got packet 4
Receiver 1 got packet 5
Receiver 2 got packet 5

答案 1 :(得分:-1)

协同程序似乎处于试验状态;我建议在使用之前等到那些成熟。见https://kotlinlang.org/docs/reference/coroutines.html#experimental-status-of-coroutines

我的平均时间,您可以尝试ThreadPool

import java.net.DatagramPacket
import java.net.DatagramSocket
import java.util.concurrent.Executors
import kotlin.concurrent.thread

fun start() {
    val pool = Executors.newFixedThreadPool(10)
    thread(isDaemon = true) {
        val socket = DatagramSocket(12345)
        while (!socket.isClosed) {
            val packet = DatagramPacket(ByteArray(1000), 0)
            socket.receive(packet)
            pool.submit({
                receive(packet)
            })
        }
    }
    pool.shutdown()
}

fun receive(packet: DatagramPacket) {
    println(String(packet.data, 0, packet.length))
}

异步IO可能很有用;您可以查看Java Selectors