Summary:When multiple threads access shared data, there will be thread safety issues.

This article is shared from the HUAWEI CLOUD community “Principles and Solutions of Multithreaded Security Issues and the Use and Difference of Synchronized and ReentrantLock”, author: Have a drink together.

Overview of Thread Safety Issues

Analysis of ticket sales

There is no problem selling 100 tickets in one window (single thread)
Single-threaded programs will not have thread safety issues

  • Multiple windows selling different tickets

The 3 windows sell tickets together, and the tickets sold are different, so there will be no problem
Multi-threaded programs, no access to shared data, will not cause problems

  • Multiple windows selling the same ticket

The tickets sold at the three windows are the same, and there will be security issues
Multi-threaded access to shared data will cause thread safety issues

Code implementation of thread safety issues

Simulated ticket sales case

Create 3 threads, open them at the same time, and sell shared tickets

public class Demo01Ticket {
 public static void main(String[] args) {
 //创建Runnable接口的实现类对象
 RunnableImpl run = new RunnableImpl();
 //创建Thread类对象,构造方法中传递Runnable接口的实现类对象
 Thread t0 = new Thread(run);
 Thread t1 = new Thread(run);
 Thread t2 = new Thread(run);
 //调用start方法开启多线程
        t0.start();
        t1.start();
        t2.start();
 }
}
public class RunnableImpl implements Runnable{
 //定义一个多个线程共享的票源
 private int ticket = 100;
 //设置线程任务:卖票
 @Override
 public void run() {
 //使用死循环,让卖票操作重复执行
 while(true){
 //先判断票是否存在
 if(ticket>0){
 //提高安全问题出现的概率,让程序睡眠
 try {
 Thread.sleep(10);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 //票存在,卖票 ticket--
 System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
                ticket--;
 }
 }
 }
}

Principle Analysis of Thread Safety Problems

Schematic diagram of thread safety issues

Analysis: Thread safety issues are normally not allowed to arise. We can allow a thread to access shared data, regardless of whether it has lost the execution right of the cpu; let other threads have to wait until the current thread sells out tickets, and other threads Tickets are being sold.

Solution to thread safety problem 1-synchronized synchronization code block

Synchronized code block: The synchronized keyword can be used in a certain block in the method, indicating that only the resources of this block are mutually exclusive.

Use synchronized to synchronize code block format:

synchronized(lock object){

Code that may have thread safety issues (code that accesses shared data)

}

The code is implemented as follows:

public class Demo01Ticket {
 public static void main(String[] args) {
 //创建Runnable接口的实现类对象
 RunnableImpl run = new RunnableImpl();
 //创建Thread类对象,构造方法中传递Runnable接口的实现类对象
 Thread t0 = new Thread(run);
 Thread t1 = new Thread(run);
 Thread t2 = new Thread(run);
 //调用start方法开启多线程
        t0.start();
        t1.start();
        t2.start();
 }
}
public class RunnableImpl implements Runnable{
 //定义一个多个线程共享的票源
 private int ticket = 100;
 //创建一个锁对象
 Object obj = new Object();
 //设置线程任务:卖票
 @Override
 public void run() {
 //使用死循环,让卖票操作重复执行
 while(true){
 //同步代码块
 synchronized (obj){
 //先判断票是否存在
 if(ticket>0){
 //提高安全问题出现的概率,让程序睡眠
 try {
 Thread.sleep(10);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 //票存在,卖票 ticket--
 System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
                    ticket--;
 }
 }
 }
 }
}

⚠️Note:

  1. The lock object in the code block can use any object.
  2. But it must be guaranteed that the lock objects used by multiple threads are the same.
  3. The function of the lock object: lock the synchronization code block, and only allow one thread to execute in the synchronization code block.

Synchronization Technology Principle Analysis

Principle of synchronization technology:

A lock object is used, which is called a synchronization lock, also called an object lock, or an object monitor

The three threads snatch the execution right of the CPU together, and whoever grabs it will execute the run method to sell tickets.

  • t0 grabs the execution right of the cpu, executes the run method, and when encountering a synchronized code block, t0 will check whether the synchronized code block has a lock object

If it is found, it will acquire the lock object and enter the synchronization to execute

  • t1 grabs the execution right of the cpu, executes the run method, and when it encounters a synchronized code block, t1 will check whether the synchronized code block has a lock object

If it is not found, t1 will enter the blocking state and will wait for the t0 thread to return the lock object. After the t0 thread executes the code in the synchronization, it will return the lock object to the synchronization code block t1 to obtain the lock object and enter the synchronization execution

Summary: The thread in the synchronization will not release the lock until the execution is completed, and the thread outside the synchronization will not be synchronized without the lock.

Solution to thread safety problem 2-synchronized ordinary synchronization method

Synchronization method: A method modified with synchronized is called a synchronization method, which ensures that when thread A executes the method, other threads can only wait outside the method.

Format:

public synchronized void payTicket(){

Code that may have thread safety issues (code that accesses shared data)

}

Code:

 public /**synchronized*/ void payTicket(){
 synchronized (this){
 //先判断票是否存在
 if(ticket>0){
 //提高安全问题出现的概率,让程序睡眠
 try {
 Thread.sleep(10);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 //票存在,卖票 ticket--
 System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
                ticket--;
 }
 }
 }

analyze:

Define a synchronization method, and the synchronization method will also lock the code inside the method, allowing only one thread to execute.

Who is the lock object of the synchronization method?

It is to implement the class object new RunnableImpl(), which is also this, so the synchronization method is the locked this object.

Solution to thread safety problem 3-synchronized static synchronization method

Synchronization method: A method modified with synchronized is called a synchronization method, which ensures that when thread A executes the method, other threads can only wait outside the method. For static methods, we use the bytecode object of the class the current method is in (classname.class).
Format:

public static synchronized void payTicket(){

Code that may have thread safety issues (code that accesses shared data)

}

Code:

 public static /**synchronized*/ void payTicketStatic(){
 synchronized (RunnableImpl.class){
 //先判断票是否存在
 if(ticket>0){
 //提高安全问题出现的概率,让程序睡眠
 try {
 Thread.sleep(10);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 //票存在,卖票 ticket--
 System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
                ticket--;
 }
 }
 }

analyze:

Who is the static synchronization method lock object?

It cannot be this, this is generated after the object is created, and the static method takes precedence over the object

The lock object of the static method is the class attribute of this class –> class file object (reflection).

Solution to thread safety problem 4-Lock lock

Methods in the Lock interface:

  • public void lock() : add synchronization lock.
  • public void unlock() : Release the synchronization lock

Steps for usage:

  1. Create a ReentrantLock object at the member location
  2. Call the method lock in the Lock interface to acquire the lock before the code that may cause security problems
  3. Call the method unlock in the Lock interface to release the lock after the code that may cause security problems

Code:

public class RunnableImpl implements Runnable{
 //定义一个多个线程共享的票源
 private int ticket = 100;
 //1.在成员位置创建一个ReentrantLock对象
 Lock l = new ReentrantLock();
 //设置线程任务:卖票
 @Override
 public void run() {
 //使用死循环,让卖票操作重复执行
 while(true){
 //2.在可能会出现安全问题的代码前调用Lock接口中的方法lock获取锁
 l.lock();
 try {
 //先判断票是否存在
 if(ticket>0) {
 //提高安全问题出现的概率,让程序睡眠
 Thread.sleep(10);
 //票存在,卖票 ticket--
 System.out.println(Thread.currentThread().getName() + "-->正在卖第" + ticket + "张票");
                    ticket--;
 }
 } catch (InterruptedException e) {
 e.printStackTrace();
 }finally {
 l.unlock();
 //3.在可能会出现安全问题的代码后调用Lock接口中的方法unlock释放锁
 //无论程序是否异常,都会把锁释放
 }
 }
 }

analyze:

java.util.concurrent.locks. Lock interface

The Lock implementation provides a wider range of locking operations than is available using synchronized methods and statements. Compared with Synchronized, the ReentrantLock class provides some advanced functions, mainly the following three items:

1. Waiting can be interrupted. When the thread holding the lock is not released for a long time, the waiting thread can choose to give up waiting. This is equivalent to Synchronized, which can avoid deadlock. This mechanism is implemented through lock.lockInterruptibly().

2. Fair lock. When multiple threads are waiting for the same lock, they must obtain the lock according to the time sequence of applying for the lock. Synchronized locks are unfair locks. The default constructor of ReentrantLock is an unfair lock created by the parameter true. It can be set as a fair lock , but the performance of the fair lock is not very good.

How to create fair and unfair locks:

//创建一个非公平锁,默认是非公平锁
Lock lock = new ReentrantLock();
Lock lock = new ReentrantLock(false);
 //创建一个公平锁,构造传参true
Lock lock = new ReentrantLock(true);

3. The lock is bound to multiple conditions, and a ReentrantLock object can bind multiple objects at the same time. ReenTrantLock provides a Condition (condition) class, which is used to wake up the threads that need to be woken up in groups, instead of either randomly waking up a thread or waking up all threads like synchronized.

The difference between ReentrantLock and Synchronized

Same point:

  1. They are all synchronized by locking;
  2. are all reentrant locks;
  3. Blocking synchronization; that is to say, if a thread acquires the object lock and enters the synchronization block, other threads accessing the synchronization block must be blocked and wait outside the synchronization block, and the cost of thread blocking and waking up is relatively high (The operating system needs to switch back and forth between the user mode and the kernel mode, which is very expensive, but it can be improved by optimizing the lock);

difference:

Click to follow and learn about Huawei Cloud’s fresh technologies for the first time~

#Principles #multithread #security #issues #solutions #HUAWEI #CLOUD #Developer #Alliances #personal #space #News Fast Delivery

Leave a Comment

Your email address will not be published. Required fields are marked *