Steve
Steve Luke wrote:Hi Faz,
Welcome to JavaRanch!
The problem here is in the reporting. You are synchronizing the counter++ part, but are not synchronizing anything else. This means that the reporting may be out of synch.
The key to remember here is that this line of code is actually multiple steps:
It can turn in to code that reads like this (not actual byte code - just an example):
The instruction can be interrupted at any point in there to allow a different thread to run. What looks like it may be happening is that Runnable2 gets through the 'get counter' part (and maybe anywhere before the flush command) first, but the context gets switched to Runnable1 before the flush occurs. So you see Runnable1's output first. Runnable1 makes several changes then the thread context switches back toe Runnable2, which already has a value for counter which is stale, it flushes the output and you get what looks like an out of sequence value, but which is probably just a stale report.
If you need to make sure the report is up to date with the counter (and prevent this sort of stale data from leaking out) then you need to put the report (the System.out.println) in the same synchronized block as the code which does the data update.
Steve
Alex Hurtt wrote:In reading this discussion I was wondering about 2 things...
1) was it really necessary to define 2 Runnables with identical function (except for the hard coded text they print out) or could one Runnable have been defined and given to two different Threads?
2) Should the counter variable be volatile? Is there a risk that synchronization alone is not enough were these two Threads to be scheduled on different CPU cores and run truly concurrently, not just time sliced/interleaved on a single processor?
Multiple core CPU's are the norm more than the exception these days and I'm in the process of learning about how this development impacts the way we think about traditional Threading issues and what we must consider going forward. My understanding is that most multi-core CPU's these days all have their own local registers (L1/L2 cache) but typically share a single L3 cache pool. Will the proper use of synchronized ensure that even if the 2 Threads are scheduled by the OS on completely separate cores, they will always read and update the value of counter from either the shared L3 cache or the system RAM pool? Or is there still a risk each thread will keep its own local copy of the counter variable in the local cache of the core on which it is running? Or do I have it completely wrong?
Steve
I am not young enough to know everything. - Oscar Wilde This tiny ad thinks it knows more than Oscar:
Smokeless wood heat with a rocket mass heater
https://woodheat.net
|