so continuing on from the previous video and we went through an example showing
how by just changing the instance variable we got a completely
different result with our multiple threads and probably at first glance you
think that it wasn't doing what it should be doing
so when i introduced terminology relating to threads i briefly mentioned
the heap and that's the applications memory that all threads share now I also
said that every thread has a thread stack and that's memory that only that
thread can access
so in other words thread one can't access threads 2's thread stack
and vice versa but they can both access the heap now local variables are stored
in the thread stack that means that each thread has its own copy of a local
variable in contrast the memory required to store an object instance value is
allocated on the heap
in other words when multiple threads are working with the same object they in
fact share the same object or share that object so they don't have their own copy
as such and so when one thread changes the value of one of the objects instance
variables the other threads will see the new value from that point forward
so how does that relate back to our application
well we're passing the same count down object to both threads and you saw that
defined on line 8 and 10 on the screen when we used a local variable
for i that was ok because when the jvm allocated the space for the local
variable it used each threads stack
consequently each thread has their own copy of i on their respective thread
stacks
however when we switched to using an instance variable the jvm allocated the
space
for i when it created the count down object and it did so at that point on the heap
now threads share the heap so in that case or in this case the two threads
don't then have their own copy of the variable I but in fact share the
variable that's on the heap
so what that means is that
so when thread one executes and change changes the the value of i and then get
suspended
so that thread 2 can execute thread 2 will then see the new value of I
as it has been updated from thread one
it won't see the value of I that it had when it was last suspended and that's
why each thread is sometimes skipping a number and why numbers can appear out of
order
so let's take a closer look at the output above in this screenshot that
I've got there and try and make some sense of it
now we have to keep in mind that a for loop is actually several statements
i'm talking about the for loop on line 36 the first time it's executed it assigns
the initial value to the variable it then checks to see whether the for
condition is met
if it is the code within the loop is executed and I'm sure you
understand that because we have been for loops throughout this course
but when we return to the for statement it will then decrement I in this case
and then check the condition again
so basically a for loop consists of several steps and a thread can be
suspended between each step this is the key point i'm making here so a thread can
be suspended between steps as an example a thread could be suspended after the for
has decremented the I variable but before the condition has been checked
again another example it could also be suspended after executing all the code
associated with the for loop but before executing the print line
so let's thinking about that let's list our some potential suspension
points here
so in the for loop a thread could be suspended just before decrementing I
just before the condition or just before printing out the value so three spots
there and thinking about it theirs actually more suspension points in this because
the print line statement involves concatenation and IO and effectively
calls multiple things but this is really a good enough
understanding of what's happening
the point here is that there's multiple points where the thread the current
thread could be suspend
so when we analyze the output all we can really be sure of is what the value of
I was when each thread printed it at that point in time
so both threads thought the value of I was ten the first time they executed the
print statement that means that thread one was suspended before it could
decrement I from 10
in other words reducing it to nine because when thread 2 print the value
it still had the value of 10
now when thread one gets the chance to print the line again
the value is 9 so from this we can guess that thread one decremented value
from 10 to 9
so how do we know that well if the thread 2 had beaten thread 1 to it
and decremented the value from ten to nine when thread one had the chance to
run again it would have decremented the value from nine to eight so it would
never have printed the value 9 at all but because it does
we know that thread one decremented it and by the same reasoning we know that the
thread one was suspended before iti could decrement the value from 9 to 8
thread 2 then decrement the value from nine to 8 and then prints
8 so the 2 threads go back and forth like this for a bit
with thread one decrementing the value printing it and suspending and then
thread 2 decrementing the value printing it and suspending now
rather than each thread being able to count down from ten to one that keeps
skipping numbers because of the interference from the other thread in
fact when problems arise because threads are inter leaving and accessing the same
resources
the situation has a name its known as thread interference and we can see why
it's called thatp now from what was shown here on the screen
these two threads keep interfering with each other because whenever they get a
chance to run the other thread has changed the value of i and as a result
each thread can no longer count down from ten to one and hit all the numbers will
also see this situation referred to as a race condition which is the more common
term for when two or more threads are writing a share
resource it is important to note that there wouldn't be a problem if both
threads are only reading the shared resource problem will only arise when at
least one other threads is writing or updating the resource
so let's think about what might have happened when the numbers two and three
were printed out of order from the pattern we've seen before we could guess
that each thread was decrementing the value checking the four condition executing
the print statement and then suspending so they're going back and forth
except on the numbers four and two were printed by thread 2
so we can guess from the output that the two threads still interleaved but thread
1 didn't get a chance to print the value 3 before it was suspended
so you might wonder you know why it printed the value 3 when it got the
chance to run again after all wouldn't thread 1 have decremented the value to 2
so why didn't thread one print the value of three
so in this case our over simplification of the possible suspension points
don't work now I mentioned that there are potential suspension points within the
print statement itself and that's what's actually happening here so let's take a
stab at how these threads are executed thread two prints the value of 4 and
has then been suspended thread one which has printed the value 5 previously and then
suspended
decrements the value to 3 thread 1 starts to execute the print statement
it builds the string that it's going to print and at that point in time the
value of i is still 3 thread one calls println and then is suspended while the
printlns method is executing but before the string is output to the
console thread 2 decrements the value to 2 and prints it and then it suspends
thread 1 continues to execute the println method and print out the string
it created when the value of i was still 3 then suspends thread 2 decrements
the value of i to 1 then prints it out
now that the value of i is 1 by threads at this point exits the for loop and terminates
now I know that is a bit of a mouthful or bit of a little bit to get your head
around but you can see that every time we run this we going to get a different
result
and there really is just no way to predict which thread is going to print
out which numbers and obviously in the case when i run this previously we've
got a completely different result
to my example image here so hopefully you can see now that threads are deceptively
simple to work with
we just have to create an object subclass from thread and call the start
method or create an instance of the thread class with a runnable object
which we've done in this section
but even when we have only two threads that are doing something
you know really simple like in this case you can see how problems and come about because
object instances are stored in the heap which is shared across threads in an
application
so I'm going to finish the video here now in the next video will continue our
discussion about race conditions
see you in the next video