[Java multithreading] synchronized (1)

1. What is synchronized?

The synchronized keyword means that this method is locked, which is equivalent to no matter which thread (such as thread A) runs to this method, it must check whether other threads B (or C, D, etc.) are using this method (or this method). Other synchronization methods of the class), if there is, wait for thread B (or C, D) that is using the synchronized method to run this method before running this thread A, if not, lock the caller, and then run it directly. It includes two usages: synchronized method and synchronized block. --Baidu Encyclopedia

2. Why use synchronized?

Synchronized is used to avoid dirty data when resources are accessed concurrently by users.
For example: for a variable i, user A assigns i to 10, but it has not been printed yet. At this time, user B changes the value of i to 200. When A prints the value of i again, the displayed result is 200.

Take a chestnut:

public class DirtyRead {

    private String username="sdf";
    private String password="123";

    public void setValue(String username, String password) {
        this.username = username;
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        this.password= password;
        System.out.println("setValue最终结果:username =" + username+",password="+password);

    }

    public synchronized void getValue(){
        System.out.println("getValue最终结果:username="+ this.username + ",password="+this.password);
    }


    public static void main(String[] args) throws Exception {
        final DirtyRead dr = new DirtyRead();
        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {
                dr.setValue("zsd", "456");

            }
        });
        t1.start();
        Thread.sleep(1000);
        dr.getValue();
    }

}

When the setValue method is not locked with synchronized, the user name and password obtained by the dr object are different from the set data. Because the thread of executing setValue has not been completed, dr obtains the username and password from the object.
dirty data

After adding a synchronized synchronization lock to the setValue method, it can be ensured that after a thread has finished operating the data, other data can be accessed, which will avoid the situation of dirty data.

3. How to use synchronized?

Synchronized method:
① When two concurrent threads access the synchronized (this) synchronized code block in the same object object, only one thread can be executed at a time. Another thread must wait for the current thread to finish executing the code block before executing the code block.
Another thread can still access non-synchronized(this) synchronized code blocks in this object.

    public synchronized void method1() {
        try {
            System.out.println(Thread.currentThread().getName());
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public void method2() {
        System.out.println(Thread.currentThread().getName());
    }
    public static void main(String[] args) {

        final MyObject mo = new MyObject();

        //t1线程先持有object对象的Lock锁,t2线程可以以异步的方式调用对象中的非synchronized修饰的方法
        //t1线程先持有object对象的lock锁,t2线程如果在这个时候调用对象中的同步synchronized方法则需要等待,也就是异步
        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {
                mo.method1();

            }
        },"t1");

        Thread t2 = new Thread(new Runnable() {

            @Override
            public void run() {
                mo.method2();

            }
        },"t2");

        t1.start();
        t2.start();
    }

Print result: t1 sleeps, t2 accesses the non-synchronized (this) synchronized code block and prints it out first
write picture description here

② Re-entrant lock

When using synchronized, when a thread obtains an object lock, it can still obtain the object lock again when it requests the object lock again. This also proves that the lock can always be obtained when calling other synchronized methods/blocks of this class inside a synchronized.
The concept of "reentrant lock" is that you can acquire your own internal lock again. For example, if one thread acquires the lock of an object, the object lock has not been released at this time. When it wants to acquire the object again The lock can still be acquired when the lock is not locked, and if the lock is not rushing in, it will cause a deadlock.

    static class Main{
        public int i =10;
         public synchronized void operationSup() {
             try {
                i--;
                System.out.println("Main print i=" + i);
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
         }
    }

    static class Sub extends Main{
        public synchronized void operationSub() {
            try {
                while(i > 0) {
                    i--;
                    System.out.println("Sub print i = " + i);
                    Thread.sleep(1000);
                    this.operationSup();
                }
            } 
                catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {
                Sub sub = new Sub();
                sub.operationSub();

            }
        });
        t1.start();
    }

write picture description here

To be continued...

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324694534&siteId=291194637