In the last few lectures, we talked about user requests being sold by threads.
And we also talked about concurrency, parallelism and asynchronous calls.
Now that we know Java threads are important for scalability, we will take a quick
look at how Java
threads are implemented in the JVM.
Before we start to analyze the connection between threads and scalability.
In order to illustrate how Java threads work under the hood, let's take a look at a
simple Java program
called Command Line Processor.
This Java program takes a user command with associated arguments and executes it.
Don't worry about the actual commands.
In fact, much of the code the letter to the commands are missing.
We would be interested in only a single command called add user.
There is a main method where the execution starts.
The program is going to start with the main thread calling this method.
When the main thread starts, the first thing it does is create a command object
from the arguments.
That's the call to extract command.
You can think about this command object as containing the command name and the
parameters necessary
to execute that particular command.
The command line processor object is created and the command object is passed to a
method called handle
command.
And the handy command will get the command name, and depending on what the name of
the command is,
that particular matter is caught since we are only interested in the add user
command.
This method will call the handle add user when the command name is ad user, you
don't care about the
rest of the command.
So finally, the main method calls the handle command method, which in turn calls
the handle add user
and so on.
So what's happening here is there is a chain of method calls which are building up.
Let's assume that the thread is frozen just after initialization of that exists
Boolean variable.
That's in the handle add user method.
Right here.
But before we discuss that, let's briefly talk about two important parts of the JVM
memory.
One is the shared heap and the second is that red stack.
Heap memory is shared by all of the threads running inside the JVM, and the stacked
memory is the memory
associated with each threat.
Every object in the JVM is created on the heap, and if different trends have
references to the same
object, then they can access this object.
That stacks, on the other hand, I tried to specify and support the cold chain that
we discussed earlier.
Local variables are kept inside that stack.
In the frames, and we will soon come to that and the kind of local variables are
stored as usually
primitive data or references to objects in the heap.
Each thread will have its own stack.
We all know that.
Let's see this in action.
When the execution of the program is frozen, just after the initialization of the
exists Boolean variable,
how will the stack look like?
So you see the main threat on the left that is represented by the arrow downwards.
The threat stack represents the stack of this main threat.
This is where the cold chain is maintained, as well as the local variables.
Each method one car will have a stack frame associated with it.
Once the method returns, the stack frame is destroyed.
You can see the stack frame over here.
So when the main method is called, the main stack frame is created and local
reference variables are
clearer on the stack frame.
When the main cause, the handle command method, another stack frame, is created for
handle command
and then another four handle add user.
All the objects are stored in the heap.
They are created in the heat.
And anybody who wants to use it needs to have a reference to that object the
following objects when
they are created, they are also created in the heap.
The Command Object command line processor and the string.
And there will be references from the stack to the heap as follows.
Take a look at the local variables inside the main method.
There are two local variables CMT and SEAL.
They are references to the heap because they are objects.
When you take a look at that exists Boolean variable, that's a primitive and the
value is kept in the
stack itself.
There is no reference to the heap over here.
Once the handle add user completes the stack frame for that method is destroyed,
once the handle command
completes, that frame is destroyed.
And the same thing happens to the main.
When the main completes, the program may terminate.
So just as a side note, in many applications when MEN completes, the program may
not terminate because
there are other non daemon threads in the JVM which are still active.
That's typical of application servers where a large pool of non daemon threads have
started up front.
So what is the size of the heap and the stack?
We can specify these sizes when the Java application starts up.
Typically, the stack size of one megabytes, but thread is common and heap size
could be on the order
of one gig or higher.
We could definitely increase or decrease these.
In Java, the one megabyte size is allocated part right up front, even though it may
not be used.
That's mandated by the U.S..
Because remember, the Java threat is backed by the US threat, which requires memory
of front.
Thing to note here is that the Java threads are basically a thin layer on top of
the orchestra, so
creating a Java thread creates an underlying OS thread under the hood.
That relationship is one to one.
One good thing about this is that the JVM is not concerned with the scheduling of
the threads on the
CPU.
The underlying OS threads are scheduled by the operating system.
But we also know that the Australia is an expensive resource.
They will prove that pretty soon, the side effect of this is that in case of an
operation, the underlying
US threat is also waiting and effectively becomes useless, even though it holds on
to the resources.
So basically, Java threads are pretty fundamental to everything.
Many threads in the JVM itself are demon threads that's implemented by Java like
garbage collector,
for example.
As developers, when we step through the code, we are essentially stepping through
the execution of
one of those threats.
When we get an exception, the factories ease the information about the stack of the
thread at the time
of the year.
This is extremely convenient for us and this is intrinsic to the style of
synchronous development we
have been doing.
Lastly, you can see the JVM auctions that are set for the command line to change
the memory setting
of the Java program that is Dash s s four stack size.
Bash Max for Max Heap size and bash Xmas for starting keepsakes.
Less of the information in this slide we have already gone through, and you can
take a brief pause
and kind of read through it.
But now that we know that Java threat is associated with an OS threat and that the
US threat is expensive,
common strategy is to handle such threats is to create a threat pool, which limits
the number of user
specific threads running in the JVM.
That's a sound strategy because we know that we cannot arbitrarily keep increasing
the number of threats.
By default, stack sizes allocated as one make for a thread and more threads in
parallel would mean
more usage of memory, and the operating system will have to deal with the context
switching of the
threads constantly.
That's an another.
So the question is, to what extent can we increase this threat pool size before we
blow up the application?
So let's do an experiment.
We would like to know what would be the maximum number of threads that can be
created in a GM.
This clearly depends on the memory of the VM and so on.
But this will give us an idea is it in the hundreds, thousands, hundreds of
thousands or millions?
Let's find that out in the next lecture.