Multi-threading -- a faster way? - java

I have a class with a getter getInt() and a setter setInt() on a certain field, say field
Integer Int;
of an object of a class, say SomeClass.
The setInt() here is synchronized-- getInt() isn't.
I am updating the value of Int from within multiple threads.
Each thread is getting the value Int, and setting it appropriately.
The threads aren't sharing any other resources in any way.
The code executed in each thread is as follows.
public void update(SomeClass c) {
while (<condition-1>) // the conditions here and the calculation of
// k below dont have anything to do
// with the members of c
if (<condition-2>) {
// calculate k here
synchronized (c) {
c.setInt(c.getInt()+k);
// System.out.println("in "+this.toString());
}
}
}
The run() method is just invoking the above method on the members updated from within the constructor by the params passed to it:
public void run() { update(c); }
When I run this on large sequences, the threads aren't interleaving much-- i see one thread executing for long without any other thread running in between.
There must be a better way of doing this.
I can't change the internals of SomeClass, or of the class invoking the threads.
How can this be done better?
TIA.
//=====================================
EDIT:
I'm not after manipulating the execution sequence of the threads. They all have the same priority. It`s just that what i see in the outcome is suggesting that the threads aren't sharing the execution time evenly-- one of them, once takes over, executing on. However, I can't see why this code should be doing this.

It`s just that what i see in the outcome is suggesting that the threads aren't sharing the execution time evenly
Well, this is exactly what you don't want if you are after efficiency. Yanking a thread from being executed and scheduling another thread is generally very costly. Therefore it's actually advantageous to do one of them, once takes over, executing on. Of course, when this is overdone you could see higher throughput but longer response time. In theory. In practice, JVMs thread scheduling is well tuned for almost all purposes, and you don't want to try changing it in almost all situations. As a rule of thumb, if you are interested in response times in millisecond order, you probably want to stay away messing with it.
tl;dr: It's not being inefficient, you probably want to leave it as it is.
EDIT:
Having said that, using an AtomicInteger may help in performance, and is in my opinion less error prone than using a lock (synchronized keyword). You need to be hitting that variable really very hard in order to get a measurable benefit though.

The JDK provides a nice solution for multi threaded int access, AtomicInteger:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicInteger.html

As Enno Shioji has pointed out, letting one thread proceed might be the most efficient way to execute your code in some scenarios.
It depends on how much cost the thread synchronization imposes in relation to the other work of your code (which we don’t know). If you have a loop like:
while (<condition-1>)
if (<condition-2>) {
// calculate k here
synchronized (c) {
c.setInt(c.getInt()+k);
}
}
and the test for condition-1 and condition-2 and the calculation of k is rather cheap compared to the synchronization cost, the Hotspot optimizer might decide to reduce the overhead by transforming the code to something like this:
synchronized (c) {
while (<condition-1>)
if (<condition-2>) {
// calculate k here
c.setInt(c.getInt()+k);
}
}
(or a rather more complicated structure by performing loop unrolling and span the synchronized block over multiple iterations). The bottom line is that the optimized code might block other threads longer but let the one owning the lock finish faster resulting in an overall faster execution.
This does not mean that a single-threaded execution was the fastest way to handle your problem. It also doesn’t mean that using an AtomicInteger here would be the best option to solve the problem. It would create a higher CPU load and possibly a small acceleration but it doesn’t solve your real mistake:
It is completely unnecessary to update c within the loop at a high frequency. After all, your threads do not depend on seeing updates to c timely. It even looks like they are not using it at all. So the correct fix would be to move the update out of the loop:
int kTotal=0;
while (<condition-1>)
if (<condition-2>) {
// calculate k here
kTotal += k;
}
synchronized (c) {
c.setInt(c.getInt()+kTotal);
}
Now, all threads can run in parallel (assuming the code you haven’t posted here doesn’t contain inter-thread dependencies) and the synchronization cost is reduced to a minimum. You could still change it to an AtomicInteger as well but that’s not that important anymore.

Answering to this
i see one thread executing for long without any other thread running in between.
There must be a better way of doing this.
You can not control how threads will be executed. JVM does this for you, and does not like you to interfere in its work.
Still you can look at yield as your option, but that also does not ensure same thread will not be picked again.
The java.lang.Thread.yield() method causes the currently executing thread object to temporarily pause and allow other threads to execute.

I've found it better to use wait() and notify() than yield. Check out this example (seen from a book)-
class Q {
int n;
boolean valueSet = false;
synchronized int get() {
if(!valueSet)
wait(); //handle InterruptedException
//
valueSet = false;
notify();//if thread waiting in put, now notified
}
synchronized void put(int n) {
if(valueSet)
wait(); //handle InterruptedException
//
valueSet = true;
//if thread in get waiting then that is resumed now
notify();
}
}
or you could try using sleep() and join the threads in the end in main() but that isn't a foolproof way

You are having public void update(SomeClass c) method in your code and this method is an instance method in which you are passing the object as parameter.
synchronized(c) in your code is doing nothing. Let me show you with some example,
So if you will make different objects of this class and then try to make them different threads like,
class A extends Thread{
public void update(SomeClass c){}
public void run(){
update(c)
}
public static void main(String args[]){
A t1 = new A();
A t2 = new A();
t1.start();
t2.start();
}
}
Then both of these t1 & t2 will have their own copies of update method and the reference variable c which you are making synchronized will also be different for both the threads. t1 calls its own update() method and t2 calls its own update() method. So synchronization won't work.
Synchronization will work when you have something common for both the threads.
Something like,
class A extends Thread{
static SomeClass c;
public void update(){
synchronized(c){
}
}
public void run(){
update(c)
}
public static void main(String args[]){
A t1 = new A();
A t2 = new A();
t1.start();
t2.start();
}
}
This way the actual concept of synchronization will be applied.

Related

Why is this code working without volatile?

I am new to Java, I am currently learning about volatile. Say I have the following code:
public class Test
{
private static boolean b = false;
public static void main(String[] args) throws Exception
{
new Thread(new Runnable()
{
public void run()
{
while(true)
{
b = true;
}
}
}).start();
// Give time for thread to start
Thread.sleep(2000);
System.out.println(b);
}
}
Output:
true
This code has two threads (the main thread and another thread). Why is the other thread able to modify the value of b, shouldn't b be volatile in order for this to happen?
The volatile keyword guarantees that changes are visible amongst multiple threads, but you're interpreting that to mean that opposite is also true; that the absence of the volatile keyword guarantees isolation between threads, and there's no such guarantee.
Also, while your code example is multi-threaded, it isn't necessarily concurrent. It could be that the values were cached per-thread, but there was enough time for the JVM to propagate the change before you printed the result.
You are right that with volatile, you can ensure/guarantee that your 2 threads will see the appropriate value from main memory at all times, and never a thread-specific cached version of it.
Without volatile, you lose that guarantee. And each thread is working with its own cached version of the value.
However, there is nothing preventing the 2 threads from resynchronizing their memory if and when they feel like it, and eventually viewing the same value (maybe). It's just that you can't guarantee that it will happen, and you most certainly cannot guarantee when it will happen. But it can happen at some indeterminate point in time.
The point is that your code may work sometimes, and sometimes not. But even if every time you run it on your personal computer, is seems like it's reading the variable properly, it's very likely that this same code will break on a different machine. So you are taking big risks.

trying to grasp basic thread synchronisation in java

public class ThreadTest implements Runnable {
private int counter;
private Date mydate = new Date();
public void upCounter1() {
synchronized (mydate ) {
for (int i = 0; i < 5; i++) {
counter++;
System.out.println("1 " + counter);
}
}
}
public void upCounter2() {
synchronized (mydate ) {
for (int i = 0; i < 5; i++) {
counter++;
System.out.println("2 " + counter);
}
}
}
public void upCounter3() {
synchronized (mydate ) {
for (int i = 0; i < 5; i++) {
counter++;
System.out.println("3 " + counter);
}
}
}
#Override
public void run() {
upCounter1();
upCounter2();
upCounter3();
}
public static void main(String[] args) {
Threadtest mtt = new Threadtest();
Thread t1 = new Thread(mtt);
Thread t2 = new Thread(mtt);
Thread t3 = new Thread(mtt);
t1.start();
t2.start();
t3.start();
}
}
I tried this code with various synchronisation techniques and I'd like to make sure I get what's happening. I've read a bunch of articles on this, but none of them broke it down enough for me.
So here's what I observed:
synchronised (this): This works only, if I give the SAME instance of Threadtest to all threads, because if I give each thread its own instance, each will get that instance's intrinsic lock and can access the methods without interruption from the other threads.
However, if I give each thread its own instance, I can do: synchronised (getClass()), because then I get the instrinsic lock of the class
Alternatively, I could do: synchronised (mydate), where the same rules apply that apply to synchronised (this). But it has the advantage of not being public. > I dont really understand this. What is the "danger" of using this?
Alternatively to synchronised (getClass()), I could also use a private static field.
However, I cannot do synchronised(Date.class).
I could synchronise the entire methods (same effecte as with synchronised-block)
making counter volatile doesn't work, because incrementing isn't a truly atomic operation
If I want to make each method accessible individually, I would make three private fields and use them in the synchronised-blocks. I then am effectively using the intrinsic locks of those fields and not of my class or instance.
I also noted that when I use the class-lock, each method is viewed as separate and I have effectively 3 ounters that go to 15. If I use the instance lock, the counter goes to 45. Is that the correct and expected behaviour?
Are my explanations and observations correct? (I basically want to make sure I draw the correct conclusions form the console output I got)
a-c; e-f are correct.
c) Alternatively, I could do: synchronised (mydate), where the same rules apply that apply to synchronised (this). But it has the advantage of not being public. > I dont really understand this. What is the "danger" of using this?
The argument is that other code may also decide to use that object as a lock. Which could cause conflict; when you know that this can never be the case then it is not such an evil thing. It is also usually more of a problem when one uses wait/notify in their code.
d) Alternatively to synchronised (getClass()), I could also use a private static field. However, I cannot do synchronised(Date.class).
You can use Date.class, it would just be a bit weird and falls into the argument discussed in c above about not polluting other classes work spaces.
g) If I want to make each method accessible individually, I would make three private fields and use them in the synchronised-blocks. I then am effectively using the intrinsic locks of those fields and not of my class or instance.
Given that the three methods share the same state, then no, this would not be wise as it would lead to races between the threads.
h) I also noted that when I use the class-lock, each method is viewed as separate and I have effectively 3 counters that go to 15. If I use the instance lock, the counter goes to 45. Is that the correct and expected behaviour?
No, this sounds wrong but I may have misunderstood you. I would expect the total to be 45 in both cases when using either this or this.getClass() as the lock.
Your code is threadsafe as it stands, if slow (you are writing to the console while holding a lock) - but better correct and slow than wrong and fast!
a) synchronised (this): This works only, if I give the SAME instance of Threadtest to all threads, because if I give each thread its own instance, each will get that instance's intrinsic lock and can access the methods without interruption from the other threads.
Your code is threadsafe either case - that is, it will give the exact same results every time. If you pass the same instance to three different threads the final line of output will be "3 45" (since there is only one counter variable) and if you give each thread its own instance there will be three lines reading "3 15". It sounds to me like you understand this.
b) However, if I give each thread its own instance, I can do: synchronised (getClass()), because then I get the instrinsic lock of the class
If you do this your code is still threadsafe, but you will get three lines reading "3 15" as above. Be aware that you will also be more prone to liveness and deadlock issues for the reason stated below.
c) Alternatively, I could do: synchronised (mydate), where the same rules apply that apply to synchronised (this). But it has the advantage of not being public. I dont really understand this. What is the "danger" of using this?
You should try to use private locks where you can. If you use a globally-visible object (e.g. this or getClass or a field with visibility other than private or an interned String or an object that you got from a factory) then you open up the possibility that some other code will also try to lock on the object that you are locking on. You may end up waiting longer than you expect to acquire the lock (liveness issue) or even in a deadlock situation.
For a detailed analysis of things that can go wrong, see the secure coding guidelines for Java - but note that this is not just a security issue.
d) Alternatively to synchronised (getClass()), I could also use a private static field. However, I cannot do synchronised(Date.class).
A private static field is preferable to either getClass() or Date.class for the reasons stated above.
e) I could synchronise the entire methods (same effecte as with synchronised-block)
Pretty much (there are currently some insignificant byte code differences), but again you should prefer private locks.
f) making counter volatile doesn't work, because incrementing isn't a truly atomic operation
Yes, you may run into a race condition and your code is no longer threadsafe (although you don't have the visibility issue mentioned below)
g) If I want to make each method accessible individually, I would make three private fields and use them in the synchronised-blocks. I then am effectively using the intrinsic locks of those fields and not of my class or instance.
You should not do this, you should always use the same lock to access a variable. As well as the fact that you could have multiple threads reading/writing to the same variable at the same time giving race condition you also have a subtler issue to do with inter-thread visibility. The Java Memory Model guarantees that writes done by one thread before a lock is released will be seen another thread when that other thread acquires the same lock. So thread 2 executing upCounter2 may or may not see the results of thread 1 executing upCounter1.
Rather than thinking of "which blocks of code do I need to execute?" you should think "which pieces of state do I need to access?".
h) I also noted that when I use the class-lock, each method is viewed as separate and I have effectively 3 ounters that go to 15. If I use the instance lock, the counter goes to 45. Is that the correct and expected behaviour?
Yes, but it has nothing to do with the object you are using for synchronisation, rather it's because you have created three different ThreadTest objects and hence have three different counters, as I explained in my answer to your first question.
Make sure that you understand the difference between three threads operating on one object and one thread operating on three different objects. Then you will be able to understand the behaviour you are observing with three threads operating on three different objects.
a) Correct
b) Correct
c) There could be some other bunch of code using your this or class in another part of your application where your class is accessible. This will mean that unrelated code will be waiting for each other to complete.
d) You cannot do synchronisation on Date.class because of the same reason above. There may be unrelated threaded methods waiting for each other unnecessarily.
e) Method synchronisation is same as class lock
g) Correct

How can I prevent two operations from interleaving with each other whilst still allowing concurrent execution?

I have two methods, foo() and bar(). There will be multiple threads calling these methods, possibly at the same time. It is potentially troublesome if foo() and bar() are run concurrently, as the interleaving of their internal logic can leave the system in an an inconsistent state. However, it it is perfectly ok, and in fact desirable, for multiple threads to be able to call foo() at the same time, and for multiple threads to be able to call bar() at the same time. The final condition is that foo() is expected to return asap, whereas there is no hard time constraint on bar().
I have been considering various ways in which it might be best to control this behaviour. Using synchronized in its simplest form doesn't work because this will block concurrent calls to each method. At first I thought ReadWriteLock might be a good fit, but this would only allow one of the methods to be called concurrently with itself. Another possibility I considered was queuing up requests for these methods on two separate queues and having a consumer which will concurrently execute every foo() in the queue, and then every bar() in the queue, but this seems like it would be difficult to tune so as to avoid unnecessary blocking of foo().
Any suggestions?
I think a good solution would be to make a separate class that controlled access to each of the methods. You would create a singleton of this class, and then use it to control when it is OK to proceed with entering either method.
This is the third iteration. This one prevents starvation.
Usage could be external to the foo() call:
em.enterFoo(Thread.currentThread());
foo();
em.exitFoo();
but would probably be cleaner as calls at the entry and exit of foo() instead, if possible.
Code:
public static class EntryManager
{
private int inFoo = 0;
private int inBar = 0;
private Queue<Thread> queue = new LinkedList<>();
public synchronized void enterBar(Thread t) throws InterruptedException
{
// Place the Thread on the queue
queue.add(t);
while(queue.peek() != t)
{
// Wait until the passed Thread is at the head of the queue.
this.wait();
}
while(inFoo > 0)
{
// Wait until there is no one in foo().
this.wait();
}
// There is no one in foo. So this thread can enter bar.
// Remove the thread from the queue.
queue.remove();
inBar++;
// Wakeup everyone.
this.notifyAll();
}
public synchronized void enterFoo(Thread t) throws InterruptedException
{
// Place the thread on the queue
queue.add(t);
while(queue.peek() != t)
{
// Wait until the passed Thread is at the head of the queue.
this.wait();
}
while(inBar > 0)
{
this.wait();
}
// There is no one in bar. So this thread can enter foo.
// Remove the thread from the queue.
queue.remove();
inFoo++;
// Wakeup everyone.
this.notifyAll();
}
public synchronized void exitBar()
{
inBar--;
// Wakeup everyone.
this.notifyAll();
}
public synchronized void exitFoo()
{
inFoo--;
// Wakeup everyone.
this.notifyAll();
}
}
I don't know of a name for that problem, so I would write my own synchronization helper object to deal with it. It sounds a lot like a reader/writer lock, except that where a reader/writer lock allows any number of readers at the same time, or exactly one writer, but not both; your lock would allow any number of foo() or any number of bar(), but not both.
The tricky part is going to be ensuring that the lock is fair. No problem if there's no contention, but what if the lock is in "foo" mode, and there's a steady stream of threads that want to call foo(), and just one or two that want to call bar(). How do the bar() threads ever get to run?
Actually, it reminds me a lot of a traffic light at a busy highway intersection. The traffic light can allow cars to flow on the east/west route, or on the north/south route, but not both. You don't want the light to switch too often and just let one or two cars through per cycle because that would be inefficient. But you also don't want the light to make drivers wait so long that they get angry.
I've got a feeling that the policy may have to be custom-tailored for your particular application. I.e., it may depend on how often the two functions are called, whether they are called in bursts, etc.
I would start from the source code of a reader/writer lock, and try to hack it up until it worked for me.

It's acceptable to always use 'this' as monitor lock?

For example I have a class with 2 counters (in multi-threaded environment):
public class MyClass {
private int counter1;
private int counter2;
public synchronized void increment1() {
counter1++;
}
public synchronized void increment2() {
counter2++;
}
}
Theres 2 increment operations not related with each other. But I use same object for lock (this).
It is true that if clients simultaneously calls increment1() and increment2() methods, then increment2 invocation will be blocked until increment1() releases the this monitor?
If it's true, does it mean that I need to provide different monitor locks for each operation (for performance reasons)?
It is true that if clients simultaneously calls increment1() and increment2() methods, then increment2 invocation will be blocked until increment1() releases the this monitor?
If they're called on the same instance, then yes.
If it's true, does it mean that I need to provide different monitor locks for each operation (for performance reasons)?
Only you can know that. We don't know your performance requirements. Is this actually a problem in your real code? Are your real operations long-lasting? Do they occur very frequently? Have you performed any diagnostics to estimate the impact of this? Have you profiled your application to find out how much time is being spent waiting for the monitor at all, let alone when it's unnecessary?
I would actually suggest not synchronizing on this for entirely different reasons. It's already hard enough to reason about threading when you do control everything - but when you don't know everything which can acquire a monitor, you're on a hiding to nothing. When you synchronize on this, it means that any other code which has a reference to your object can also synchronize on the same monitor. For example, a client could use:
synchronized (myClass) {
// Do something entirely different
}
This can lead to deadlocks, performance issues, all kinds of things.
If you use a private final field in your class instead, with an object created just to be a monitor, then you know that the only code acquiring that monitor will be your code.
1) yes it's true that increment1() blocks increment2() and vice versa because they both are implicitly synchronizing on this
2) if you need a better performance consider the lock-free java.util.concurrent.atomic.AtomicInteger class
private AtomicInteger counter1 = new AtomicInteger();
private AtomicInteger counter2 = new AtomicInteger();
public void increment1() {
counter1.getAndIncrement();
}
public void increment2() {
counter2.getAndIncrement();
}
If you synchonize on the method, as what you did here, you lock the whole object, so two thread accessing a different variable from this same object would block each other anyway.
If you want to syncrhonize only a counter at a time so two thread won't block each other while accessing different variables, you have to add the two counters here in two synchronized block, and use different variables as the "lock" of the two blocks.
You are right it will be a performance bottleneck if you use same Object. You can use different lock for individual counter or use java.util.concurrent.atomic.AtomicInteger for concurrent counter.
Like:
public class Counter {
private AtomicInteger count = new AtomicInteger(0);
public void incrementCount() {
count.incrementAndGet();
}
public int getCount() {
return count.get();
}
}
Yes the given code is identical to the following:
public void increment1() {
synchronized(this) {
counter1++;
}
}
public oid increment2() {
synchronized(this) {
counter2++;
}
}
which means that only one method can be executed at the same time. You should either provide different locks (and locking on this is a bad idea to begin with), or some other solution. The second one is the one you actually want here: AtomicInteger
Yes if multiple threads try to call methods on your object they will wait trying to get the lock (although the order of who gets the lock isn't guaranteed.) As with everything there is no reason to optimise until you know this is the bottle neck in you code.
If you need the performance benefits that can be had from being able to call both operations in parallel, then yes, you do not to provide different monitor objects for the different operations.
However, there is something to be said for premature optimization and that you should make sure that you need it before making your program more complex to accommodate it.

Questions on Concurrency from Java Guide

So I've been reading on concurrency and have some questions on the way (guide I followed - though I'm not sure if its the best source):
Processes vs. Threads: Is the difference basically that a process is the program as a whole while a thread can be a (small) part of a program?
I am not exactly sure why there is a interrupted() method and a InterruptedException. Why should the interrupted() method even be used? It just seems to me that Java just adds an extra layer of indirection.
For synchronization (and specifically about the one in that link), how does adding the synchronize keyword even fix the problem? I mean, if Thread A gives back its incremented c and Thread B gives back the decremented c and store it to some other variable, I am not exactly sure how the problem is solved. I mean this may be answering my own question, but is it supposed to be assumed that after one of the threads return an answer, terminate? And if that is the case, why would adding synchronize make a difference?
I read (from some random PDF) that if you have two Threads start() subsequently, you cannot guarantee that the first thread will occur before the second thread. How would you guarantee it, though?
In synchronization statements, I am not completely sure whats the point of adding synchronized within the method. What is wrong with leaving it out? Is it because one expects both to mutate separately, but to be obtained together? Why not just have the two non-synchronized?
Is volatile just a keyword for variables and is synonymous with synchronized?
In the deadlock problem, how does synchronize even help the situation? What makes this situation different from starting two threads that change a variable?
Moreover, where is the "wait"/lock for the other person to bowBack? I would have thought that bow() was blocked, not bowBack().
I'll stop here because I think if I went any further without these questions answered, I will not be able to understand the later lessons.
Answers:
Yes, a process is an operating system process that has an address space, a thread is a unit of execution, and there can be multiple units of execution in a process.
The interrupt() method and InterruptedException are generally used to wake up threads that are waiting to either have them do something or terminate.
Synchronizing is a form of mutual exclusion or locking, something very standard and required in computer programming. Google these terms and read up on that and you will have your answer.
True, this cannot be guaranteed, you would have to have some mechanism, involving synchronization that the threads used to make sure they ran in the desired order. This would be specific to the code in the threads.
See answer to #3
Volatile is a way to make sure that a particular variable can be properly shared between different threads. It is necessary on multi-processor machines (which almost everyone has these days) to make sure the value of the variable is consistent between the processors. It is effectively a way to synchronize a single value.
Read about deadlocking in more general terms to understand this. Once you first understand mutual exclusion and locking you will be able to understand how deadlocks can happen.
I have not read the materials that you read, so I don't understand this one. Sorry.
I find that the examples used to explain synchronization and volatility are contrived and difficult to understand the purpose of. Here are my preferred examples:
Synchronized:
private Value value;
public void setValue(Value v) {
value = v;
}
public void doSomething() {
if(value != null) {
doFirstThing();
int val = value.getInt(); // Will throw NullPointerException if another
// thread calls setValue(null);
doSecondThing(val);
}
}
The above code is perfectly correct if run in a single-threaded environment. However with even 2 threads there is the possibility that value will be changed in between the check and when it is used. This is because the method doSomething() is not atomic.
To address this, use synchronization:
private Value value;
private Object lock = new Object();
public void setValue(Value v) {
synchronized(lock) {
value = v;
}
}
public void doSomething() {
synchronized(lock) { // Prevents setValue being called by another thread.
if(value != null) {
doFirstThing();
int val = value.getInt(); // Cannot throw NullPointerException.
doSecondThing(val);
}
}
}
Volatile:
private boolean running = true;
// Called by Thread 1.
public void run() {
while(running) {
doSomething();
}
}
// Called by Thread 2.
public void stop() {
running = false;
}
To explain this requires knowledge of the Java Memory Model. It is worth reading about in depth, but the short version for this example is that Threads have their own copies of variables which are only sync'd to main memory on a synchronized block and when a volatile variable is reached. The Java compiler (specifically the JIT) is allowed to optimise the code into this:
public void run() {
while(true) { // Will never end
doSomething();
}
}
To prevent this optimisation you can set a variable to be volatile, which forces the thread to access main memory every time it reads the variable. Note that this is unnecessary if you are using synchronized statements as both keywords cause a sync to main memory.
I haven't addressed your questions directly as Francis did so. I hope these examples can give you an idea of the concepts in a better way than the examples you saw in the Oracle tutorial.

Categories

Resources