Concurrent access to objects and variables - Part 2

Static synchronization method synchronized method and synchronized(class) code block

The synchronized keyword is passed to the static method to lock the class, while the synchronized keyword is added to the non static method to lock the object.

public class MainClass {
    synchronized public void printStringA()  {
        String a = Thread.currentThread().getName();
        String b = Thread.currentThread().getName() + "a";
        System.out.println(a);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(b);
    }

    synchronized  public static void printStringB() {
        String a = Thread.currentThread().getName();
        String b = Thread.currentThread().getName() + "b";
        System.out.println(a);
        System.out.println(b);
    }
}

public class ThreadA extends Thread {
    private MainClass mainClass;

    public ThreadA(MainClass mainClass) {
        this.mainClass = mainClass;
    }

    @Override
    public void run() {
            mainClass.printStringA();
    }
}

public class ThreadB extends Thread {
    private MainClass mainClass;

    public ThreadB(MainClass mainClass) {
        this.mainClass = mainClass;
    }

    @Override
    public void run() {
            mainClass.printStringB();
    }
}

public class RunClass {
    public static void main(String[] args) throws InterruptedException {
        MainClass mainClass = new MainClass();
        ThreadA threadA = new ThreadA(mainClass);
        threadA.start();
        ThreadB threadB =new ThreadB(mainClass);
        threadB.start();
    }
}   

Output result

Thread-0
Thread-1
Thread-1b
Thread-0a

From the output results, we can see that the execution of the two methods is asynchronous. The reason for asynchronous execution is that one is object lock and the other is class lock. If you still don't understand, please look at the following methods.

public class MainClass {
    synchronized public static void printStringA()  {
        String a = Thread.currentThread().getName();
        String b = Thread.currentThread().getName() + "a";
        System.out.println(a);
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(b);
    }

   synchronized public static void printStringB() {
        String a = Thread.currentThread().getName();
        String b = Thread.currentThread().getName() + "b";
        System.out.println(a);
        System.out.println(b);
    }
}

public class RunClass {
    public static void main(String[] args) throws InterruptedException {
        MainClass mainClass = new MainClass();
        MainClass mainClass2 = new MainClass();
        ThreadA threadA = new ThreadA(mainClass);
        threadA.start();
        Thread.sleep(100);
        ThreadB threadB =new ThreadB(mainClass2);
        threadB.start();
    }
}   

Output result

Thread-0
Thread-0a
Thread-1
Thread-1b

This is the difference between class lock and object lock.

Constant pool property of data type String

Look at the program first.

public class MainClass {
    public void printStringB(String stringParam) {
        try {
            synchronized (stringParam) {
                while (true) {
                    System.out.println(Thread.currentThread().getName());
                    Thread.sleep(1000);
                }
            }
        } catch ( InterruptedException ex) {
            ex.printStackTrace();
        }
    }
}

public class ThreadA extends Thread {
    private MainClass mainClass;

    public ThreadA(MainClass mainClass) {
        this.mainClass = mainClass;
    }

    @Override
    public void run() {
            mainClass.printStringB("AA");
    }
}

public class ThreadB extends Thread {
    private MainClass mainClass;

    public ThreadB(MainClass mainClass) {
        this.mainClass = mainClass;
    }

    @Override
    public void run() {
        mainClass.printStringB("AA");
    }
}

public class RunClass {
    public static void main(String[] args) throws InterruptedException {
        MainClass mainClass = new MainClass();
        MainClass mainClass2 = new MainClass();
        ThreadA threadA = new ThreadA(mainClass);
        threadA.setName("a");
        threadA.start();
        ThreadB threadB =new ThreadB(mainClass2);
        threadB.setName("b");
        threadB.start();

    }
}    

Output result

a
a
a
a
a
a
...

Continuously output a, thread b has not been executed at all, why is this? Because both values of string are AA, which is the impact of string constant pool. AA is within the cache range of string constant pool, so the synchronization method holds the same object, so thread b cannot be executed.

In most cases, you can't use string objects as lock objects, but use other objects, such as object objects.

Other constant pools also need to be careful, such as shaping.

public class MainClass {
    public void printStringB(Object object) {
        try {
            synchronized (object) {
                while (true) {
                    System.out.println(Thread.currentThread().getName());
                    Thread.sleep(1000);
                }
            }
        } catch ( InterruptedException ex) {
            ex.printStackTrace();
        }
    }
}

public class ThreadA extends Thread {
    private MainClass mainClass;

    public ThreadA(MainClass mainClass) {
        this.mainClass = mainClass;
    }

    @Override
    public void run() {
            mainClass.printStringB(new Object());
    }
}

public class ThreadB extends Thread {
    private MainClass mainClass;

    public ThreadB(MainClass mainClass) {
        this.mainClass = mainClass;
    }

    @Override
    public void run() {
        mainClass.printStringB(new Object());
    }
}

Output result

b
a
b
a
b
a
b
a
...

Posted by ph8edsicness on Thu, 02 Jan 2020 15:17:17 -0800