Examples of thread safety problems and solutions (ReentrantLock)

1. Preface

  • This article is a follow-up to the previous article. The case is the same case. It is very simple. It is the case of taking the order number when going to teacher Tian for dinner. Without too much introduction, you can also see the detailed introduction of the previous article, as follows:

    1.1 synchronized solves thread safety problems

    Examples of thread safety problems and solutions (synchronized).

2. Examples of thread safety problems and Solutions

  • wait for

    2.1 existence of thread safe code

    • For convenience, I've removed the "T" here and directly use numbers. That's not the focus of our demonstration. Let's look at the code directly:
package com.liu.susu.thread.lock.example3;

/**
 * @FileName OrderNumberRun
 * @Description Start three threads to generate the order number
 * @Author susu
 * @date 2022-03-03
 **/
public class OrderNumberRun implements Runnable {

    private int number = 1;//The pick-up order number in line starts from the 1st

    @Override
    public void run() {
        //Suppose there is a discount for the top 100 orders today
        while (true) {
            if (number <= 100) {
                System.out.println(Thread.currentThread().getName() + "-Mr. Tian's house, take the order number as-->" + number);
                number++;
            }else {
                break;
            }
        }
    }
}
class clientTest3 {
    public static void main(String[] args) {
        OrderNumberRun orderNumberRun = new OrderNumberRun();
        Thread thread1 = new Thread(orderNumberRun);
        Thread thread2 = new Thread(orderNumberRun);
        Thread thread3 = new Thread(orderNumberRun);
        thread1.setName("Thread 1");
        thread2.setName("Thread 2");
        thread3.setName("Thread 3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}
  • Effect display:

    It's obviously unsafe. It's also introduced in the previous article. I won't say much. Let's focus on the treatment scheme

    2.2 solving thread safety with ReentrantLock

    • The modified code is shown in the figure below:
    • The complete code is as follows:
package com.liu.susu.thread.lock.example4;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @FileName OrderNumberRun
 * @Description Start three threads to generate the order number
 * @Author susu
 * @date 2022-03-03
 **/
public class OrderNumberRun implements Runnable {

    private int number = 1;//The pick-up order number in line starts from the 1st
    /**
     * 1.Instantiate ReentrantLock to define the lock
     *   If the parameter fair is set to true -- > fair lock (that is, three threads take the lock fairly to prevent one thread from taking out the order number), the default fair is false
     */
    private final ReentrantLock lock = new ReentrantLock(true);
    @Override
    public void run() {
        //Suppose there is a discount for the top 100 orders today
        while (true) {
            try {
                //2. Call the lock() method to lock
                lock.lock();
                if (number <= 100) {
                    System.out.println(Thread.currentThread().getName() + "-Mr. Tian's house, take the order number as-->" + number);
                    number++;
                }else {
                    break;
                }
            } finally {
                //3. Call the unlock() method to unlock
                lock.unlock();
            }
        }
    }
}

class clientTest4 {
    public static void main(String[] args) {
        OrderNumberRun orderNumberRun = new OrderNumberRun();
        Thread thread1 = new Thread(orderNumberRun);
        Thread thread2 = new Thread(orderNumberRun);
        Thread thread3 = new Thread(orderNumberRun);
        thread1.setName("Thread 1");
        thread2.setName("Thread 2");
        thread3.setName("Thread 3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}
  • The operation effect is as follows:

3. The difference between synchronized and ReentrantLock

3.1 explanation

3.1.1 similarities

  • It is certain that both synchronized and ReentrantLock can solve thread safety problems
  • ReentrantLock refers to a reentrant lock. Like synchronized, it belongs to a reentrant lock;
    Reentrant lock: if the same thread obtains the lock resource for the first time, it has the right to obtain the lock again. This is the reentry of the lock!
  • Both are locked synchronization and blocking synchronization, that is, if a thread obtains an object lock and enters the synchronization block, other threads accessing the synchronization block must block and wait outside the synchronization block, The cost of thread blocking and wake-up is relatively high (the operating system needs to switch back and forth between user state and kernel state, which is very expensive, but it can be improved by lock optimization).

3.1.1 differences

(1) Implementation difference

  • Use lock initialization to select fair locks and non fair locks
  • Lock lock only has code block lock, and synchronized has code block lock and method lock
  • synchronized is an implicit lock that automatically releases the synchronization monitor (automatically releases the lock)
    Lock is a display lock. You need to manually start synchronization (lock() method locks), and you need to manually unlock it when you end synchronization (call the unlock () method)
  • For Synchronized, it is a keyword of the java language and a mutual exclusion at the native syntax level, which needs to be implemented by the JVM. ReentrantLock is jdk5 The mutex at the API level provided after 0 needs the lock() and unlock() methods together with the try/finally statement block to complete
  • Synchronized is more convenient to use, and the compiler ensures the locking and release of locks. ReenTrantLock needs to declare manually to add and release locks. In order to avoid deadlock caused by forgetting to release locks manually, it is best to declare the release of locks in finally.

(2) Performance difference

  • Using lock lock, the JVM will spend less time to schedule threads, with better performance and good scalability (providing more subclasses)

3.2 table comparison

contrastsynchronizedReentrantLock
appearAlwaysJDK5.0 NEW
ReentrancyReentrantReentrant
Lock typeFair lock / unfair lockUnfair lock
Release formThe call to unlock () must be shownAutomatic release monitor
flexibilityNot flexible enough
Lock implementation mechanismRely on AQSMonitor Mode
  • In the part to be further studied, what is the implementation principle of the lock mechanism?

Keywords: SQL

Added by pixeltrace on Sat, 05 Mar 2022 13:59:13 +0200