我正在通过两本非常有帮助的书自学并发:
- JVM 中的并发,来自 Brian Goetz。
- 学习 Scala 中的并发编程,来自 Aleksandar Prokopec。
作为对我知识的测试,我正在尝试构建一个具有固定数量线程的裸线程池。
该线程正在轮询任务队列。
ThreadPool 为我提供了一种在队列中插入任务的方法,返回一个 MyFutureTask[T]
,我希望它是 Java 中实际 FutureTask[T]
的模拟,以便我稍后可以检索该值。
def addTask[T](theTask: () => T): MyFutureTask[T] = queue.synchronized {
val myFutureTask: MyFutureTask[T] = new MyFutureTask[T] {
override val task: () => T = theTask
}
queue.enqueue(myFutureTask)
queue.notify()
myFutureTask
}
如果我不关心我提交的任务的返回值(即 Runnable),那么我可以为任务队列指定一个正确的类型,即 MyFutureTask[Unit]
:
私有(private) val 队列 = mutable.Queue[MyFutureTask[Unit]]()
但是,当任务返回我稍后想要检索的值时,这将要求任务队列没有正确的类型,因为我需要向 ThreadPool 提交多个任务,每个任务都有不同的返回类型(task1 : () => String
、task2: () => Int
、task3: () => SomeProperType
...),这将导致:
私有(private) val 任务 = mutable.Queue[MyFutureTask[_]]()
这让我感到不安,因为在 Scala 中,所有未键入的内容都会被拒绝。
所以我的问题是:
1 - 我上面说的有错吗?我错过了一些导入步骤吗?或者这根本不是正确的方法?
2 - 在实际的ThreadPool实现中任务队列没有正确的类型是不可避免的吗?
3 - 如果这是不可避免的,它有什么缺点吗?这还值得担心吗?
谢谢
最佳答案
这与 JVM 中运行的所有语言都继承的“类型删除”有关。简而言之,泛型由编译器检查,然后被删除,因此如果您想要混合类型的集合,则该集合的类型参数必须是所有可能类的父类(super class)。是的,当您从集合中检索数据时,您将获得父类(super class)。
我认为 Shapeless 的 HList 可以让您在列表中保存多种类型。
否则,您需要施放。如果必须的话,我会使用与此类似的函数:
def dequeue[T](tasks: mutable.Queue[MyFutureTask[Any]]) = tasks.dequeue().asInstanceOf[MyFutureTask[T]]
关于java - 维护线程池任务队列的类型信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52020195/