Mantaining type information on the queue of tasks of a ThreadPool

Mantaining type information on the queue of tasks of a ThreadPool



I am self learning concurrency with the 2 very helpful books:

- Concurrency in the JVM, from Brian Goetz.

- Learning Concurrent Programming in Scala, from Aleksandar Prokopec.



As a test to my knowledge, I am trying to build a bare ThreadPool with a fixed number of threads.

This threads are polling on a queue of tasks.

The ThreadPool provides me a method to insert tasks in a queue, returning a MyFutureTask[T], which I hope is an emulation of the actual FutureTask[T] in java, so that I can retrieve the value later.


MyFutureTask[T]


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



If I do not care about the return value of the tasks I submit (i.e. Runnable) then I can have a proper type for the queue of tasks, namely MyFutureTask[Unit]:

private val queue = mutable.Queue[MyFutureTask[Unit]]()


MyFutureTask[Unit]



private val queue = mutable.Queue[MyFutureTask[Unit]]()



However, when the tasks return a value that I later want to retrieve, this would require the tasks queue not to have a proper type, as I would need to submit to the ThreadPool multiple tasks, each with a different return type ( task1 : () => String, task2: () => Int, task3: () => SomeProperType ... ), which would lead to:


() => String


() => Int


() => SomeProperType




private val tasks = mutable.Queue[MyFutureTask[_]]()



private val tasks = mutable.Queue[MyFutureTask[_]]()



This leaves me uneasy, as in Scala everything that is not typed is frowned upon.



So my questions are:

1 - Have I said anything wrong above? Am I missing some import step? Or is this not the correct approach at all?

2 - Is it unavoidable for the queue of tasks not to have a proper type in the actual ThreadPool implementations?

3 - If it is unavoidable, are there any disadvantages to it? Is that even a concern?



Thanks,




2 Answers
2



This is related to "type erasure" in the JVM that is inherited by all the languages that run on the JVM. In short, generics are checked by the compiler and then they are erased, so if you want a collection of mixed type, the collection's type-parameter must be the super-class of all the possible classes. And yes, when you retrieve the data from the collection you are left with the super class.



I think that Shapeless's HList let you keep multiple types in a list.



Otherwise, you need to cast. If I have to, I use a function similar to this:


def dequeue[T](tasks: mutable.Queue[MyFutureTask[Any]]) = tasks.dequeue().asInstanceOf[MyFutureTask[T]]



I don't see why your queue needs to know about a the return type at all.
Just make it operate on Runnables:


Runnables


def addTask[T](theTask: () => T): Future[T] =
val result = Promise[T]()
val myFutureTask: Runnable = new Runnable
override val run()
result.complete(Try theTask() )


queue.synchronized
queue.enqueue(myFutureTask)
queue.notify()

result.future






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

How do I collapse sections of code in Visual Studio Code for Windows?

Node.js puppeteer - Use values from array in a loop to cycle through pages