synchronized Java learning record of concurrent

Disclaimer: This article is a blogger original article, reproduced, please attach Bowen link! https://blog.csdn.net/Little_fxc/article/details/87861917

synchronized Java learning record of concurrent

Brief introduction

Now learning about how to use synchronizedkeywords, it's no longer on the principle of learning within the range.

Security problems instance variables

How variable is an internal methods private variables , this variable is safe.

But if this variable is an instance variable , so multiple threads operating this variable becomes unsafe (if you do not use synchronizedit)

The many uses of keyword synchronized

  • Designated lock object: a given object locking, synchronization code to be obtained before entering the given object lock
  • Examples of the method is directly applied to: the current instance is equivalent to locking, in the synchronization code to be obtained before the current instance of the lock
  • Direct effect on the static method: corresponding to the current class lock, before entering the synchronization code to acquire a lock of the current class

Examples of methods act directly on the error model

package com.littlefxc.examples.base.thread.sync;

/**
 * 指定加锁对象的错误示例:两个线程访问的不是同一个对象
 *
 * @author fengxuechao
 * @date 2019/2/20
 **/
public class AccountSync1 implements Runnable {

    static volatile int money = 0;

    public static void main(String[] args) {
        AccountSync1 account1 = new AccountSync1();
        AccountSync1 account2 = new AccountSync1();
        Thread t1 = new Thread(account1);
        Thread t2 = new Thread(account2);
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(money);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100000; i++) {
            money++;
        }
    }
}

result

Here Insert Picture Description

The results of our expected results (200,000) is obviously different.

Why is this so?

A closer look at the code, we money++this operation do in fact have two steps, to lock the code, we run()add methods synchronized,
becomes

@Override
public synchronized void run() {
    for (int i = 0; i < 100000; i++) {
        money++;
    }
}

And then run the code, still error. ( I have been locked up ??? )

In a closer look at the code, you can find our code there are two threads, but the two threads access different instances, this is not the cause of the desired result.
Modify the code is two threads access the same instance. code show as below:

package com.littlefxc.examples.base.thread.sync;

/**
 * 指定加锁对象的错误示例:两个线程访问的不是同一个对象
 *
 * @author fengxuechao
 * @date 2019/2/20
 **/
public class AccountSync1 implements Runnable {

    static volatile int money = 0;

    public static void main(String[] args) {
        AccountSync1 account1 = new AccountSync1();
//        AccountSync1 account2 = new AccountSync1();
        // 使两个线程访问同一实例
        Thread t1 = new Thread(account1);
        Thread t2 = new Thread(account1);
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(money);
    }

    @Override
    public synchronized void run() {
        for (int i = 0; i < 100000; i++) {
            money++;
        }
    }
}

Now run the code can get the desired result of 200,000.

In short, the above code Keywords synchronizedact on an instance method, which means that to enter the synchronizedpre-modification method,
multiple threads must acquire a lock object instance of the same, that is, access to the same object instance, so as to ensure the security thread .

Demonstration of error specified lock object

We will slightly modify the above code, the object instance in the synchronized action specified, for example this.

package com.littlefxc.examples.base.thread.sync;

/**
 * @author fengxuechao
 * @date 2019/2/21
 **/
public class AccountSync2 implements Runnable {

    static volatile int money = 0;

    @Override
    public void run() {
        synchronized (this) {
            for (int i = 0; i < 100000; i++) {
                money++;
            }
        }
    }

    public static void main(String[] args) {
        AccountSync2 account1 = new AccountSync2();
        AccountSync2 account2 = new AccountSync2();
        Thread t1 = new Thread(account1);
        Thread t2 = new Thread(account2);
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(money);
    }
}

result

Here Insert Picture Description

This error can be seen in the example just changes the synchronizedkeyword into the internal method, and acts on this,
this thisrepresents the current instance of the object. From this analysis we can assume that the cause of the error code is not the same instance of an object two threads access.

Modify the code:

package com.littlefxc.examples.base.thread.sync;

/**
 * @author fengxuechao
 * @date 2019/2/21
 **/
public class AccountSync2 implements Runnable {

    static volatile int money = 0;

    @Override
    public void run() {
        synchronized (this) {
            for (int i = 0; i < 100000; i++) {
                money++;
            }
        }
    }

    public static void main(String[] args) {
        AccountSync2 account1 = new AccountSync2();
//        AccountSync2 account2 = new AccountSync2();
        Thread t1 = new Thread(account1);
        Thread t2 = new Thread(account1);
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(money);
    }
}

In short, the above code Keywords synchronizedact on an object instance that is entering the synchronizedpre-modified block of code,
multiple threads must acquire the same lock object instance, which is the access to the same object instance, so as to ensure thread Safety.

Direct effect on the static method

However, there is a way to ensure that multiple threads can access multiple object instances and still guarantee thread-safe way. It is to add the static method synchronized.

package com.littlefxc.examples.base.thread.sync;

/**
 * @author fengxuechao
 * @date 2019/2/21
 **/
public class AccountSync3 implements Runnable {

    static volatile int money = 0;

    @Override
    public void run() {
        for (int i = 0; i < 100000; i++) {
            increase();
        }
    }

    private synchronized static void increase() {
        money++;
    }

    public static void main(String[] args) {
        AccountSync3 account1 = new AccountSync3();
        AccountSync3 account2 = new AccountSync3();
        Thread t1 = new Thread(account1);
        Thread t2 = new Thread(account2);
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(money);
    }
}

Analysis of the above code, we need to know that everything is an object in Java, so Java class itself is a target.
In the Java JVM is initialized when there is a sequence of:

  1. First initialize the parent class's static code
  2. Initialize the subclass of static code
  3. (For instance is created, if not created instance, the back is not performed) non-static initialization code of the parent class (variable definitions)
  4. Constructor initializes the parent class
  5. Setup sub-class non-static code (variable definitions)
  6. Setup sub-class constructor

In short, synchronizedmodification static method locks is the current class itself.
Verify my thoughts, transform it into the following code:

package com.littlefxc.examples.base.thread.sync;

/**
 * @author fengxuechao
 * @date 2019/2/21
 **/
public class AccountSync4 implements Runnable {

    static volatile int money = 0;

    @Override
    public void run() {
        synchronized (AccountSync4.class) {
            for (int i = 0; i < 100000; i++) {
                money++;
            }
        }
    }

    public static void main(String[] args) {
        AccountSync4 account1 = new AccountSync4();
        AccountSync4 account2 = new AccountSync4();
        Thread t1 = new Thread(account1);
        Thread t2 = new Thread(account2);
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(money);
    }
}

After testing, I thought was right. Meanwhile, in the beginning of this article points out synchronizedthe many uses of fact based on different manifestations of the same principle.
To lock the operation of memory space, you need to be able to match this key to the lock,
so that the thread within a certain time only to get the lock before they can access the lock locked space
, for example, this can also be kind of transformation synchronized modification of immutable objects such as strings.

synchronized ("abc") {
    ...
}

Guess you like

Origin blog.csdn.net/Little_fxc/article/details/87861917