so let's now go through and give an example to demonstrate a race condition
now we could easily have both threads count down to one without skipping
numbers by not passing the same count down object to both threads
so instead what we're going to do is create two count down objects and pass 1 to
thread one and the other to thread 2 because of course at the moment as you
can see on lines 8 and 10
we're passing the same object so by doing it this way by creating an object
for each and passing a different one to each of our threads both objects are
stored in the heap and are shared but since thread 1 would only work on count down
object one and thread 2 on count down object 2
there wouldn't be any interference so let's change the code just to
demonstrate that now so i'm going to change that we're going to use...
...and lets also create a second one....and then we're going to
pass....
so let's run that and see what happens going to run it a few times just to
confirm what you should be seeing here is that there's no interference
we're still getting objects running or the results rather printed out in a
different order
and that's because the operating system is suspending the threads and starting
them again
but what you can see here this is now there's no interference so we've got
each number or each thread rather is successfully counting down from ten to
one
but unfortunately this solution often wont work in a real world applications
so as an example imagine if the objects represented here were bank accounts or
employee records
we can't provide each thread with a different object it wouldn't make sense
to do that
so every time a bank manager or employee file is accessed and changed
we have to use the same object to maintain integrity of the data in
other words how do we know what the bank balance should be after several threads
have changed it so in the case of bank accounts
there could be several threads waiting to change the bank balance at the same
time there could be a thread making an automatic deposit
perhaps a thread making a schedule build payment
and the owner of the account doing some online banking so in order to ensure the
integrity of the bank balance value we need to allow multiple threads to change
it but we also need to prevent a race condition which is thread interference
which we talked about and went through in the previous video
now fortunately Java provides us with the way to control when a thread can change
a value in the heap
the process of controlling when threads execute code and therefore when they can
access the heap is called synchronization
so we can synchronize methods and statements now when a method is
synchronized only one thread can execute that at a time
so when the thread is executing the method all other threads that want to
call the method or any other synchronized method in that class will suspend until
the thread running the method exits it then another thread can run a
synchronized method then another etc to be clear if a class has three
synchronize methods then only one of these methods can ever run at a time and
only on one thread now since only one thread can execute a synchronized method
at a time
threads can't interleave when running a synchronized method
so what that does is it prevents thread interference within synchronized
methods but not outside of those methods
so if the same instance variables reference within a synchronized method
are also reference outside it you know coded in multiple threads can run and that a
particular code isn't synchronized then we may still see thread interference
when working with threads we have to synchronize all areas where we think all
you know where interference can happen so let's change our example back now to
only using one count down objects since we have established a real world application
couldn't have separate objects as such it wouldn't work
I'm just going to undo those changes
and just to confirm when we run it we should see that the threads are now
skipping numbers again
so we are getting that interference again so to synchronize a method all we
really have to do is add the synchronized keyword to a method
declaration
so it seems though the work is being done in the do count down method we just need to
change this by adding synchronized now when we run it you can see that
thread 1 count downs without skipping any numbers and then thread 2
does the same and notice when i run it again
we're getting the same results every time I run this and that's because
by adding the synchronized keyword
we are now saying that we want this whole method to run before another
thread gets access to and that's why you can see thread 1 finishes in the entire
thread or the entire method and then thread 2 get its chance to do the same
so in this scenario they're never going to interleave because only one of them
can execute the do count down method at a time
now unfortunately we can't synchronize constructors and if you think about it
it wouldn't really make sense if we could do that
only one thread can construct an instance and until the constructor has
finished executing the instants won't be available for other threads to use
anyway but what we can do is synchronized any other method
so that's one way to prevent a race condition
the second way we can do that we can prevent a race condition is to
synchronize a block of statements rather than an entire method so every java
object has what's called it's our call and its intrinsic lock and will also
see this reference to as a monitor
so we can synchronize a block of statements that work with an object by
forcing threads to acquire the objects lock before they execute the statement
block now only one thread can hold the lock at a time so other threads that want
the lock will be suspended until the running thread releases it then 1 and
only one of the waiting threads can get the lock and continue executing so
looking at our code in the do count down method
the only code we really have to synchronize is the for loop
thread interference doesn't affect the rest of the code since we're setting a
color based on the thread name
so what objects will we used to synchronize the for loop
we can't use the counter variable I because it's a primitive type not an
object and primitive types don't have intrinsic locks so at first glance the
first thought might be to use the color object to synchronize the for loop so
let's try that and see what happens so to the synchronize a set of statements we
just put them inside a synchronized block so let's look at doing that so I'm
going to add some code here on line 36
we're going to type....we're going to use color....
....
so let's run that and see what happens
and what we'll do is we'll remove the synchronized key word from our method
now because we no longer want to synchronize the entire method we are
now doing the alternative approach to just synchronizing a block of code so remove
that and run that you can see we've got a different result
and clearly there's now some interference again so why is this
happening because you know only one thread can hold the color object lock at
a time
the only one thread should be able to execute the for statement that's in the
synchronized block on line 36 the other thread should have to wait until
the first thread has finished its count down but as you can clearly see
by me running this example we're seeing the same type of result we got when we
weren't synchronizing at all
the problem here is that we're using a local variable to synchronize and you
recall that local variables are stored in the thread stack each thread will
create its own copy of the local variable and each copy is an object that
has its own lock thread one gets the lock for its copy and continues
executing and thread 2 gets locked for its copy and it continues executing when
we want a synchronize using an object
we have to use an object that threads will share so that they're both
competing for the same lock using local variables as a result won't work
the only exception to this is using a string variable and the reason for that
is string objects are reused within the jvm in other words the jvm use a string
pools for allocation of string objects
I'm only mentioning this now because you may see examples of a local string
variable being used to synchronize code and you'll be wondering why that works
in the synchronize code we've got here using the color local variable doesn't
work
so that's really the only exception to the rule as a general rule it's easy to
just remember not to use local variables to synchronize full stop now before we fix our
example I really should reiterate that when using a local object variable the
object references stored in the thread stack but the object values are stored
on the heap
now since the threads will each create their own copy of the object
so the object references will then be different there won't be any
interference
even though the object values are in the heap essentially the thread stack will
only ever contain primitive values and object references and to be fair
function references but that's really outside the scope of this lecture and
not related to race conditions
so let's fix our example so we work out that color doesn't work here
because it's a local variable so it would actually make sense to synchronize
using the count down object that the thread share
so we can do this by synchronizing on this so let's try it by removing the
reference to the color and changing it to this....
and we try running it and just run a few times and as you can see that at this
point the threads no longer interleave or skip numbers only one thread can run
the for loop at a time and you can also synchronize static methods and you can
also use static objects when you do that the lock that use is owned by the class
object associated with the objects class
so I'm going to finish the video here in the next video will continue our
discussion about synchronization
we're going to a bit more detail about that see you in the next video