Thread Pool can reuse threads to run new tasks.
In this lesson, you're going to use a thread pool to run your tasks.
Creating a threat is pretty slow, and you should avoid the habit of always creating a new threat whenever
there's a new task.
Let's remove the target variable and define a target array.
Targets with three values.
Well, say point five point eight point three.
So as you can probably guess, our application has to generate three guesses and really important.
Let's reduce the precision by two decimal places to shorten the execution time because what if it just
has a really hard time guessing one of the numbers?
We don't want it to take forever.
This amount of decimal places is accurate enough.
And since we're going to be repeating a lot of the same code, let's just shorten it.
For instance, we can just define the callable directly inside the future task.
OK.
And now our difference function is going to expect another parameter, that parameter is INT index.
And we're going to evaluate the difference between the target at index.
Against the number that was generated by the application.
Generate number is also going to receive an index and index.
And given what we know so far, your first instinct would be to create a new thread for each new task,
which, by the way, isn't the best practice, but for now we'll just do it anyway.
I will copy and paste this two more times.
Here, the task will generate a number that is accurate to the first target.
This one is going to do the same thing for the second target and third.
We'll call this future to feature three.
We'll call this thread three and thread for.
OK.
After creating the threads, we can start them right away, or we can say thread three dots starts.
Thread for Dodd starts.
OK, this is already looking not the best, but anyways, I'm going to change my print statements here
to, uh, forget the returned values for now, we'll just say finished running background operations.
And now how can we make sure that we'll delete this for now?
And now, how can we make sure that every single thread has finished running by the time we get to this
line?
Remember that future dog get wait until a thread is finished executing its task, and it's going to
get the final value that the callable is holding onto?
So what we will have to do is forget this.
We'll just say FutureGen two more times.
OK, and now if you run the code.
You know what, the term of this, I think you get the point by now, it's not blocking the main thread.
And for the number of decimal places that we specified, this performed relatively well, not the best.
Now the take home message is that after a thread finishes running, it dies and then you have to create
a new threat once that thread dies.
Say you have another task, then you have to create another threat and another.
Now, let's imagine I wanted to run generate number a few hundred times.
Would you expect to create 100 threads?
Uh, probably not.
A good idea.
That would be incredibly taxing because for each thread that you create, there are so many slow operations
that the JVM needs to perform.
So you might think, OK, yeah, I'm creating so many threads.
So many of my tasks are being performed at the same time.
But there is actually a trade off when you create too many threads because they consume a lot of resources.
There are so many slow operations that the JVM needs to perform for each thread, and it's actually
going to make your application slower.
So the point is we can use a thread pool.
Imagine we have a fixed thread pool with three threads every time we submit a task to the thread pool.
It's going to use one of its threads to perform the task.
In this case, we submitted three tasks.
And after every thread performs its task, the thread stays active, it doesn't die.
Let's just imagine we have another task to thread pool.
It's going to reuse one of the threads to perform the task.
So right here, what we're going to do is create a fixed thread pool with three threads executor service.
Well, just call it executor.
Is equal to from the executors, we're going to create a new fixed threat pool that has three threads.
And then what I can do is just directly submit every single callable to the thread pool.
Oh, if you look here, actually, you can see that the submit method is overloaded to accept a runnable
task or a callable task.
We're going to submit a callable task.
Or three, for that matter?
One and two.
And already this is looking a lot cleaner.
And what's beautiful about this is as soon as you submit a task, it already starts running in the background,
so we don't need to say that the red dots start or anything.
When you submit a callable, however, it returns a future object that we can use to extract the return
value after the threat is finished.
So here I can say future.
Double.
Future is equal to executor, does submits.
Can do the same thing here.
And here.
OK.
And if we run the app now.
Everything still works, and you'll notice the app doesn't shut down.
Hope you understand why we created a threat pool with a size of three.
And it's likely that each thread executes one task.
After all, the tasks are complete, the threads haven't died, they're still active.
So at the end, once every thread is finished, we need to make sure we shut down the executor service.
Executor, Dutch shutdown.
What's beautiful about this is I can even submit to other tasks and still only have three threads.
The thread pool is just going to reuse two of its threads to perform the remaining tasks.
Running that.
And it finishes fairly quickly.
Now keep in mind that the task scheduler is really a random concurrent execution is unpredictable in
itself, so if for some reason it ends up being a bit too slow for you, feel free to increase it to
four threads, or you can even reduce the precision.
But in any case?
Things are working out pretty well.
Now you might be asking what is the ideal thread, pool size when you're performing CPU bound tasks,
so tasks whose speed of execution depends on the speed of the CPU?
Then a good rule of thumb is to set the number of threads equal to the number, of course, that your
application has access to.
And inside each other, you can obtain the number of cards your app has access to by using the following
code.
First, we're going to get the runtime.
And how many processors are available to the applications runtime?
I should get eight.
You should get a different number because we're not using the same computer.
Now, I'm just going to use this as my number of threats.
You know what we'll say it's for clarity and numb threads is equal to runtime.
All right.
This works out pretty well.
A threat pool retains an active number of threats.
The rule of thumb is favor reusing threads over creating new ones.
In other words, use a thread pool.