Java multithreading learning (two) synchronized keyword (1)

Java multithreading learning (two) synchronized keyword (1)

Please note the address for reprinting: blog.csdn.net/qq_34337272...

Java multithreading learning (2) will be divided into two articles to introduce the synchronized synchronization method and the other to introduce the synchronized synchronization statement block .

Series of articles Portal:
Java Multithreading Learning (1) Getting Started with Java Multithreading

Java multithreading learning (two) synchronized keyword (1)

Java multithreading learning (two) synchronized keyword (2)

Java multithreading learning (three) volatile keyword

Java multi-threaded learning (four) wait/notify (wait/notify) mechanism

The series of articles will be updated with priority and the WeChat public account "Java Interview Customs Manual", welcome the attention of the majority of Java programmers and technical hobby personnel.

(1) synchronized synchronization method

Mind maps in this section:

Mind map source files + mind map software. Follow WeChat public account: "Java Interview Clearance Manual" Reply keyword: "Java multithreading" is free to receive.

1 Introduction

In the field of concurrent programming in Java, the synchronized keyword has always been a veteran role. A long time ago, many people would call it a "heavyweight lock". However, after JavaSE 1.6, it has mainly included the introduction of biased locks and lightweight locks and other various optimizations in order to reduce the performance consumption caused by acquiring and releasing locks. It has become not so heavy in some cases. .

This article will not introduce the implementation principle of the synchronized keyword, but more about the use of the synchronized keyword. If you want to know about it, you can check out Fang Tengfei's "The Art of Concurrent Programming in Java".

Two-variable security

The "non-thread-safe" problem exists in "instance variables". If it is a private variable inside the method, there is no "non-thread-safe" problem, and the result is "thread-safe".

If two threads operate the instance variables in the object at the same time, "non-thread safe" will appear. The solution is to add the synchronized keyword before the method. We have already talked about it in the previous article and posted the corresponding code, so we won't post the code here.

More than three objects and multiple locks

Look at the example first:

HasSelfPrivateNum.java

public class HasSelfPrivateNum {

    private int num = 0;

    synchronized public void addI(String username) {
        try {
            if (username.equals("a ")) {
                num = 100;
                System.out.println("a set over! ");
               //hread.sleep(2000) 
                Thread.sleep(2000);
            } else {
                num = 200;
                System.out.println("b set over! ");
            }
            System.out.println(username + " num=" + num);
        } catch (InterruptedException e) {
           //TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

} 

ThreadA.java

public class ThreadA extends Thread {

    private HasSelfPrivateNum numRef;

    public ThreadA(HasSelfPrivateNum numRef) {
        super();
        this.numRef = numRef;
    }

    @Override
    public void run() {
        super.run();
        numRef.addI("a ");
    }

} 

ThreadB.java

public class ThreadB extends Thread {

    private HasSelfPrivateNum numRef;

    public ThreadB(HasSelfPrivateNum numRef) {
        super();
        this.numRef = numRef;
    }

    @Override
    public void run() {
        super.run();
        numRef.addI("b ");
    }

} 

Run.java

public class Run {

    public static void main(String[] args) {

        HasSelfPrivateNum numRef1 = new HasSelfPrivateNum();
        HasSelfPrivateNum numRef2 = new HasSelfPrivateNum();

        ThreadA athread = new ThreadA(numRef1);
        athread.start();

        ThreadB bthread = new ThreadB(numRef2);
        bthread.start();

    }

} 

Running results:
a num=100 pause for a while before executing the

two threads ThreadA and ThreadB in the above example respectively access the same-named synchronous methods of different instances of the same class, but the effect is indeed asynchronous.

Why is this so?

This is because the locks acquired by synchronized are all object locks, not a piece of code or method as a lock. So in the above example, which thread executes the method with the synchronized keyword first, which thread holds the lock Lock of the object to which the method belongs, then other threads can only be in a waiting state, provided that multiple threads access the same An object. There are obviously two objects in this example.

In this example, two HasSelfPrivateNum objects are created, so two locks are generated. When the reference of ThreadA is executed to the runThread.sleep(2000) statement in the addI method, ThreadB will "take the opportunity to execute". Therefore, the execution result is shown in the figure above (Note: due to runThread.sleep(2000), "a num=100" pauses for two seconds before outputting)

4.synchronized methods and lock objects

From the above, we know that the locks acquired by synchronized are all object locks, not a piece of code or method as a lock. If multiple threads access the same object, which thread executes the method with the synchronized keyword first, which thread holds the method, and other threads can only be in a waiting state. If multiple threads access multiple objects, it is not necessarily because multiple objects will generate multiple locks.

So let's think about the effect when multiple threads access the non-synchronized type method in the same object?

The answer is: the non-synchronized type method will be called asynchronously, and the solution is also very simple to add the synchronized keyword before the non-synchronized type method.

5.internal organs reading

When a dirty read occurs, the value has been changed by other threads when the instance variable is read.

PublicVar.java

public class PublicVar {

    public String username = "A ";
    public String password = "AA ";

    synchronized public void setValue(String username, String password) {
        try {
            this.username = username;
            Thread.sleep(5000);
            this.password = password;

            System.out.println("setValue method thread name="
                    + Thread.currentThread().getName() + " username="
                    + username + " password=" + password);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    //synchronized 
     public void getValue() {
        System.out.println(" getValue method thread name="
                + Thread.currentThread().getName() + " username=" + username
                + " password=" + password);
    }
} 

ThreadA.java

public class ThreadA extends Thread {

    private PublicVar publicVar;

    public ThreadA(PublicVar publicVar) {
        super();
        this.publicVar = publicVar;
    }

    @Override
    public void run() {
        super.run();
        publicVar.setValue("B ", "BB ");
    }
} 

Test.java

public class Test {

    public static void main(String[] args) {
        try {
            PublicVar publicVarRef = new PublicVar();
            ThreadA thread = new ThreadA(publicVarRef);
            thread.start();

            Thread.sleep(200);//

            publicVarRef.getValue();
        } catch (InterruptedException e) {
           //TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
} 

Operation result:

Solution: add the synchronized keyword before the getValue() method.

The operation result after adding the synchronized keyword:

6.synchronized lock reentry

The concept of "reentrant lock" is: You can acquire your own internal lock again. For example, a thread has acquired the lock of an object, and the object lock has not been released yet. It can still be acquired when it wants to acquire the lock of this object again. If the lock is not reentrant, it will cause a deadlock.

Service.java

public class Service {

    synchronized public void service1() {
        System.out.println("service1 ");
        service2();
    }

    synchronized public void service2() {
        System.out.println("service2 ");
        service3();
    }

    synchronized public void service3() {
        System.out.println("service3 ");
    }

} 

MyThread.java

public class MyThread extends Thread {
    @Override
    public void run() {
        Service service = new Service();
        service.service1();
    }

} 

Run.java

public class Run {
    public static void main(String[] args) {
        MyThread t = new MyThread();
        t.start();
    }
} 

Operation result:

In addition, reentrant locks are also supported in the environment inherited by parent and child classes

Main.java:

public class Main {

    public int i = 10;

    synchronized public void operateIMainMethod() {
        try {
            i--;
            System.out.println("main print i=" + i);
            Thread.sleep(100);
        } catch (InterruptedException e) {
           //TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
} 

Sub.java:

public class Sub extends Main {

    synchronized public void operateISubMethod() {
        try {
            while (i > 0) {
                i--;
                System.out.println("sub print i=" + i);
                Thread.sleep(100);
                this.operateIMainMethod();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
} 

MyThread.java:

public class MyThread extends Thread {
    @Override
    public void run() {
        Sub sub = new Sub();
        sub.operateISubMethod();
    }
} 

Run.java:

public class Run {
    public static void main(String[] args) {
        MyThread t = new MyThread();
        t.start();
    }
} 

operation result:

Explain that when there is a parent-child class inheritance relationship, the child class can call the synchronization method of the parent class through the "reentrant lock".

In addition, when an exception occurs, the lock held by the lock will be automatically released.

7.synchronization does not have inheritance

If the parent class has a method with the synchronized keyword, the child class inherits and overrides this method.
But synchronization cannot be inherited, so you still need to add the synchronized keyword in the subclass method.

Reference:
"Java Multithreaded Programming Core Technology"

Welcome to follow my WeChat public account (share various Java learning resources, interview questions, and reply keywords for enterprise-level Java practical projects to receive for free):