[Concurrent Programming] Synchronized solves shared variable analysis

The main content of this article:
Problems caused by shared variables
How to use Synchronized to solve the inconsistency of read and write data caused by shared variables

1. Thinking about the problems caused by sharing

1.1 The embodiment of shared variables in java

Thinking: Two threads perform increment and decrement on a static variable with an initial value of 0, each 5000 times. Is the result 0?

static int counter = 0;
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                counter++;
            }
        }, "t1");
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                counter--;
            }
        }, "t2");
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        log.debug("{}",counter);
    }

1.2 Problem analysis

The above result may be a positive number, a negative number, or zero. why? Because the increment and decrement of static variables in Java are not atomic operations, to fully understand it, you must analyze it from the bytecode
For example, for i++ (i is a static variable), The following JVM bytecode instructions will actually be generated:

getstatic i // 获取静态变量i的值
iconst_1 // 准备常量1
iadd // 自增
putstatic i // 将修改后的值存入静态变量i

The corresponding i-- is similar:

getstatic i // 获取静态变量i的值
iconst_1 // 准备常量1
isub // 自减
putstatic i // 将修改后的值存入静态变量i

Then let's take a look at Java's memory model, how to remind the self-increment and self-decrement operation:
Insert image description here

If it is a single thread, the 8 lines of code will be executed sequentially (not interleaved), no problem
Insert image description here
However, in the case of multi-threading, these 8 lines of code may be interleaved.< a i=2> For example:

Insert image description here

1.3 The concept of critical section

  • There is no problem with a program running multiple threads
  • The problem lies in multiple threads accessingshared resources
    Multiple threads readingshared resources Interlace and problems will ariseshared resources
    The instruction occurs when multiple threads read and write operations onIn fact, there is no problem
  • If there are multi-threaded read and write operations onshared resources within a code block, this code block is called< a i=3>critical section

For example, the critical section in the following code

static int counter = 0;
    static void increment()
    // 临界区
    {
        counter++;
    }
    static void decrement()
    // 临界区
    {
        counter--;
    }

2. Synchronized solution

In order to avoid race conditions in critical sections, there are many ways to achieve the goal.

  • Blocking solutions: synchronized, Lock
  • Non-blocking solution: atomic variables

This article uses a blocking solution: synchronized to solve the above problem, commonly known as [Object Lock]. It uses a mutual exclusion method so that at most one thread can hold [Object Lock] at the same time, and other threads can think about it. It will be blocked when acquiring this [object lock]. This ensures that the thread that owns the lock can safely execute the code in the critical section without worrying about thread context switching.

Note
Although both mutual exclusion and synchronization in Java can be accomplished using the synchronized keyword, they are still different:
Mutual exclusion is To ensure that race conditions in the critical section occur, only one thread can execute the critical section code at the same time
Synchronization is due to the different execution sequence and order of threads, which requires one thread to wait for other threads to run to a certain Dot

2.1 synchronized syntax

synchronized(对象) // 线程1, 线程2(blocked)
{
 临界区
}

synchronized on method

class Test{
        public synchronized void test() {

        }
    }
    等价于
    class Test{
        public void test() {
            synchronized(this) {

            }
        }
    }
class Test{
        public synchronized static void test() {
        }
    }
    等价于
    class Test{
        public static void test() {
            synchronized(Test.class) {

            }
        }
    }

2.2 Solution

static int counter = 0;
    static final Object room = new Object();
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                synchronized (room) {
                    counter++;
                }
            }
        }, "t1");
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                synchronized (room) {
                    counter--;
                }
            }
        }, "t2");
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        log.debug("{}",counter);
    }

We can understand it this way:

  • The object in synchronized (object) can be imagined as a room (room). There is a unique entrance (door). Only one person can enter the room at a time for calculation. Threads t1 and t2 can be imagined as two people.
  • When thread t1 executes synchronized(room), it is like t1 enters the room, locks the door, takes away the key, and executes the count++ code in the door.
  • At this time, if t2 also runs to synchronized(room), it finds that the door is locked and can only wait outside the door. A context switch occurs and is blocked.
  • Even if t1's CPU time slice unfortunately runs out and is kicked out of the door (don't misunderstand that locking the object can continue to execute), the door is still locked at this time, t1 still holds the key, and t2 The thread is still blocked and cannot enter. You can only open the door and enter when it is t1's turn next time and you get the time slice again.
  • When t1 finishes executing the code in the synchronized{} block, it will come out of obj's room and unlock the door, wake up the t2 thread and give him the key. Only then can the t2 thread enter the obj room, lock the door, take the key, and execute its count-- code

Represent with diagrams
Insert image description here

The article is continuously updated. You can follow the public account below or search "Last Rosemary" on WeChat to obtain the project source code and read it immediately to obtain more complete link information.

Guess you like

Origin blog.csdn.net/qq_38374397/article/details/134683610