简体   繁体   中英

How really static synchronized method works in Java?

I'm trying to explore static synchronized method I got the theoretical concept that it's acquire lock on class, not on instance. But I'm failed to create an example where I Can test it.

Here I have created the Code to test, But both instance are accessing static synchronized method at the same time.

class Demo{
    public static synchronized void a(){
        System.out.println("A Method " +  Thread.currentThread().getName());
    }
}
public class StaticSyn{
    public static void main(String[] args){
        Demo obj = new Demo();
        Demo obj2 = new Demo();

        Thread one = new Thread(){
            @Override
            public void run(){
                int i=0;
                while(i<5){
                    obj.a();
                try{
                    Thread.sleep(100);
                }catch(InterruptedException e){

                }
                    i++;
                }
            }
        };
        Thread two = new Thread(new Runnable(){
            @Override
            public void run(){
                int i=0;
                while(i<5){
                    obj2.a();
                    try{
                        Thread.sleep(100);
                    }catch(InterruptedException e){     }
                    i++;
                }
            }
        });

        one.start();
        two.start();
    }
}

With static synchronized I'm getting this output.

A Method Thread-0
A Method Thread-1
A Method Thread-1
A Method Thread-0
A Method Thread-1
A Method Thread-0
A Method Thread-0
A Method Thread-1
A Method Thread-1
A Method Thread-0

Without static keyword I'm getting this output.

A Method Thread-0
A Method Thread-1
A Method Thread-1
A Method Thread-0
A Method Thread-0
A Method Thread-1
A Method Thread-0
A Method Thread-1
A Method Thread-1
A Method Thread-0

So, where is the problem? and How I can test that Just one object is accessing static synchronized method.

You can add a sleep in your method a() as next:

public static synchronized void a(){
    System.out.println("Before sleep: A Method " +  Thread.currentThread().getName());
    try{
        Thread.sleep(100);
    } catch(InterruptedException e){
        Thread.currentThread().interrupt();
    }
    System.out.println("After sleep: A Method " +  Thread.currentThread().getName());
}

You will then see that you won't have 2 threads executing this block at the same time like in the next output, indeed you never have twice consecutively Before sleep :

Before sleep: A Method Thread-0
After sleep: A Method Thread-0
Before sleep: A Method Thread-1
After sleep: A Method Thread-1
Before sleep: A Method Thread-0
After sleep: A Method Thread-0
Before sleep: A Method Thread-1
After sleep: A Method Thread-1
Before sleep: A Method Thread-0
After sleep: A Method Thread-0
Before sleep: A Method Thread-1
After sleep: A Method Thread-1
Before sleep: A Method Thread-0
After sleep: A Method Thread-0
Before sleep: A Method Thread-1
After sleep: A Method Thread-1
Before sleep: A Method Thread-0
After sleep: A Method Thread-0
Before sleep: A Method Thread-1
After sleep: A Method Thread-1

What is the difference between static synchronized method and synchronized method?

The main difference is the object used to synchronize the access.

Static

For example doing this:

class Demo {
    public static synchronized void a() {
        // Rest of the method
    }
}

Is equivalent to this:

class Demo {
    public static void a() {
        synchronized (Demo.class) {
            // Rest of the method
        }
    }
}

In other words in case of a static method it uses the object representing the class itself to synchronize the access.

Non Static

For example doing this:

class Demo {
    public synchronized void a() {
        // Rest of the method
    }
}

Is equivalent to this:

class Demo {
    public void a() {
        synchronized (this) {
            // Rest of the method
        }
    }
}

In other words in case of a non static method it uses the current instance of the class to synchronize the access.

You need to make the a() method run long to make sure the method calls aren't overlapping. This is one way of doing it:

package com.example;

public class Demo {

    public static synchronized void a() {
        for (int i = 0; i < 5; i++) {
            System.out.println("A Method " +  Thread.currentThread().getName());
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        final Demo obj = new Demo();
        final Demo obj2 = new Demo();

        Thread one = new Thread() {
            @Override
            public void run() {
                obj.a(); // same as Demo.run() 
            }
        };
        Thread two = new Thread() {
            @Override
            public void run() {
                obj2.a(); // same as Demo.run() 
            }
        };

        one.start();
        two.start();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM