I was going through the ThreadPool pattern and it resembles the Object Pool pattern. The only difference that I can think of is that most explanations about the ThreadPool explicitly mentioned the use of task queue while the Object Pool pattern is not explicitly stated. Can someone please explain to me the difference between these two patterns?
Yes, these patterns are very similar, but they're also different in very crucial ways.
With object pool, all you do is check out an object for your usage and you do whatever you want to do with that object. Object pool is used as a way to borrow ownership/control of an object for a duration of execution. An object pool is typically used when the creation of that object is expensive, awkward, or impossible because the objects are connected to a unique resource. For example a Continuous Integration system may have multiple copies of the build context (i.e. filesystem folder or a docker container), creating new build context is quite expensive so a pool is used to manage access to the build context. Another example is creating new TCP/TLS connection requires handshakes which involves multiple roundtrips to a server that's probably half way around the world, so a connection pool may be used to reuse connections. Another example may be the use of pool to limit usage of a coprocessor (e.g. GPU), a physical machine may only have access to a limited number of physical GPU, so a pool may be used because you can't just create a new GPU out of thin air.
Thread pooling is a kind of an object pool, and internally a thread pool likely may contain use an object pool, however when people talk about thread pool, usually they aren't really talking about the underlying object pool, but rather thread pool is really just a particular type of implementation of the Executor pattern. The difference between typical object pool and thread pool is that with a thread pool, rather than checking out an object, you submit a task to be completed asynchronously and in parallel. The thread pool will execute that task in the pool of worker threads that waits on the pool's task queue.
The difference between a Thread Pool and an Object Pool is the same as the difference between a Toyota Corolla and a Vehicle.
An Object Pool is a pool of objects. A Thread Pool is a pool of objects, but not any kind of object, only threads.
They both serve the same basic purpose: objects that are expensive to create, expensive to destroy, limited in number, or any combination thereof, are stored instead of destroyed when they are no longer needed, and re-used instead of created when a "new" one is needed.
Note that in the general case, Object Pool is an anti-pattern. Objects shouldn't be expensive. If they are, then there is something wrong with your runtime environment. In an OO language, you should not need not to think about whether you can afford creating an object or not. Objects are the basis of OO, if your runtime can't handle a couple million objects, get a better one.
Likewise, in multi-threaded programming, threads are the basic building blocks, and your runtime should not restrict you in how you are using them. For example, on the BEAM/HiPE VM, you can create 10 million processes (note that processes are much more expensive than threads; threads basically only have an instruction pointer, a stack, and some limited thread-local storage, processes have their own heap, their own protected memory, and on BEAM/HiPE even their own garbage collector) on a 15 year old 32-bit laptop without even breaking a sweat, so it's not like it is impossible to make threads cheap.
However, we live in the real world, and there are some runtime environments where threads are so expensive that re-using them is a necessity. For example, on Linux, a thread weighs 4 KiByte or 8 KiByte compared to a BEAM/HiPE process, which is only ~300 Byte. And that's where the Thread Pool comes in.
We create a certain number of threads (typically on the same order as we have CPU cores for computation plus a couple of ones for I/O). And then we create a lightweight abstraction (let's call it a
CodeSnippet) that is basically the same thing as a thread or a process, but lightweight, and we can create as many of those as we want. When we want to execute one of those code snippets, we pull a thread from our pool, run it, grab the result, dispose the code snippet (remember, it's lightweight, so creating and destroying them is no problem), and put the thread back in the pool. That way, we can have a lightweight abstraction of a thread-like thing mapped to actual threads without having to create a large number of threads or restrict ourselves to only using a small number of concurrent objects.
A thread pool is a kind of object pool, except that the threads involved in pooling hold an operating system resource (whether temporarily or permanently).
This means that there could — in theory — be an implementation of thread pooling that does not pool (language) objects and instead creates a new (language) thread object with an existing operating system thread from the thread pool. In such an implementation we would still acknowledge thread pooling but not object pooling.
The management of the object in an object pool and thread pool may differ as well, as the thread pool objects may be managed in a highly controlled way and with respect to specific operating system interactions, whereas an object pool perhaps managed more simply.
The thread pool is specifically intended for the purpose of more efficient task execution, whereas the object pool design pattern is more general.