Learning Java, use of synchronized keyword

2019-01-11 12:24发布

问题:

so i was testing with synchronized keyword. Here is an example that I tried:

public class MyTest {
    static int i = 0;
    public static void main(String[] args) {
        new Thread(t1).start();
        new Thread(t2).start();
    }

    private static void countMe(String name){
        i++;
        System.out.println("Current Counter is: " + i + ", updated by: " + name);
    }

    private static Runnable t1 = new Runnable() {
        public void run() {
            try{
                for(int i=0; i<5; i++){
                    countMe("t1");
                }
            } catch (Exception e){}

        }
    };

    private static Runnable t2 = new Runnable() {
        public void run() {
            try{
                for(int i=0; i<5; i++){
                    countMe("t2");
                }
            } catch (Exception e){}
       }
    };
}  

When I run it, the output of calling countMe() method from two threads generates this output:

Current Counter is: 1
Current Counter is: 2
Current Counter is: 4
Current Counter is: 5
Current Counter is: 6
Current Counter is: 7
Current Counter is: 3
Current Counter is: 8
Current Counter is: 9
Current Counter is: 10  

And when I change the method countMe() to:

private synchronized static void countMe(){
        i++;
        System.out.println("Current Counter is: " + i);
}  

I get this output:

Current Counter is: 1
Current Counter is: 2
Current Counter is: 3
Current Counter is: 4
Current Counter is: 5
Current Counter is: 6
Current Counter is: 7
Current Counter is: 8
Current Counter is: 9
Current Counter is: 10  

Although this gives me clear understanding the purpose of synchronized, I want to know is there any other reason as well, that we can use synchronized. Or what I have done here, is the only eason why we need the use of this synchronized keyword?

Thanks.

EDIT: Another thing that I am confused with is that in first output why the counter went to 3 after 7. It seems a bit impossible to me, but similar results do happen every time I try, is this normal?

回答1:

Two things:

First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.

Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads.

Synchronized methods enable a simple strategy for preventing thread interference and memory consistency errors: if an object is visible to more than one thread, all reads or writes to that object's variables are done through synchronized methods. (An important exception: final fields, which cannot be modified after the object is constructed, can be safely read through non-synchronized methods, once the object is constructed).

source: http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html



回答2:

Vulkanino gave a good answer to your main question, so I'll only address your question about 3 printing after 7.

The 3 can print after the 7 because there is actually a lot more byte code in your statements than Java code.

I'll expand on that.

You call

System.out.println("Current Counter is: " + i);

and it occurs in one line of Java code, but really what happens is a string is created and then that string is passed to println. The println method itself has to do a bit of processing before it actually writes the line to the console.

Conceptually, something like the following is happening.

String printlnString = "Current Counter is: 3"
--> maybe the other thread executes here
System.out.println(printlnString);
--> or maybe the other thread executes here
i is now equal to 7 and the console has "Current Counter is: 7"
println writes "Current Counter is: 3" to console