A brief description of thread safety issues and synchronization mechanisms

 1 Introduction

 Thread safety is a common type of problem in multi-threaded programming. It means that when multiple threads access shared resources at the same time, problems such as data competition and deadlock may occur, resulting in program errors or exceptions.

 2. Frequently asked questions

(1) Data competition: When multiple threads access the same resource at the same time, data inconsistency will result. For example, in a multi-threaded environment, multiple threads modify the same variable at the same time, which may cause the value of the variable to be unpredictable.

(2) Deadlock: Multiple threads wait for each other to release resources at the same time, causing the program to fail to continue running and enter a deadlock state.

(3) Non-atomic operations: Some operations require multiple instructions to complete. If multiple threads execute these operations at the same time, partial execution will occur, resulting in incorrect program results.

(4) Memory leaks: Due to improper program design, memory may not be reclaimed, resulting in memory leaks.

3. Solution: use thread synchronization mechanism

(1) Synchronous code block:

synchronized(monitor (object lock)){         //code that needs to be synchronized...

}

(2) Synchronization method:

public synchronized void method name(){         //code that needs to be synchronized...

}

(3) Note:

a. The monitor (object lock) can be any object, but the monitor (object lock) used in concurrent threads must be the same object.

b. It can be understood in this way: each thread has a door to access shared resources, but the key to open the door is only one monitor (object lock), which ensures that only one thread can access shared resources at the same time.

c. The synchronized monitor in the synchronization method is fixed to the object this of the current class. Therefore, if you want to use the synchronization method in the thread class, you can only use implements Runnable, not extends Thread: because if you want to use multi-threading after implements Runnable, you only need to create one thread class object and multiple Thread class objects, so It is guaranteed that there is only one this of the thread class; but if you want to use multi-threading after extends Thread, you need to create multiple objects of the thread class. At this time, there are multiple thiss in the thread class, which does not meet the requirements of the monitor.

d. Although the synchronization mechanism avoids the problem of thread safety, it also reduces the efficiency of thread concurrency.

4. Practice

Let's take a ticketing system as an example to understand thread safety and synchronization mechanisms.

package ThreadSafe;

public class TicketSystem {
	//售票系统
	public int tickets = 100;//总票数是100
}
package ThreadSafe;
	//买票线程
public class TicketThread extends Thread{
	public TicketSystem ts;//售票系统
	//初始化售票系统
	public TicketThread(TicketSystem ts) {
		this.ts = ts;
	}
	public void run() {
		for(int i=0;i<50;i++) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"买到票:"+ts.tickets);//输出当前线程所买到的票序
			ts.tickets--;//每售出一张票,总票数-1
		}
	}
}
package ThreadSafe;

public class Main {
	public static void main(String[]args) {
		TicketSystem ts = new TicketSystem();//售票系统
		TicketThread t1 = new TicketThread(ts);//购票线程
		t1.setName("线程A");
		t1.start();
		TicketThread t2 = new TicketThread(ts);
		t2.setName("线程B");
		t2.start();
	}
}

In the above code, two threads buy tickets at the same time, change the data of tickets, and take a look at the running results without using the synchronization mechanism:

It can be seen that in the result, two threads bought the same ticket, and there was a jump order.

The reasons for the above situation may be:

When thread A executes the operation of ts.tickets-- for the first time, it only completes the operation of tickets-1, but before updating the value of tickets, it is thread B's turn to execute, resulting in the Tickets is still 100, which means that two threads bought the 100th ticket at the same time. Then thread B completed the operation of ts.tickets--, tickets=99 at this time, it was thread A's turn again, and thread A updated the data tickets = tickets-1 on the basis of tickets=99, causing tickets to directly become 98 .

Next, we first use the synchronization code block to change the above code. Since the ticketing system ts is only created once in the thread class, we can use ts as a synchronized monitor.

public void run() {
		for(int i=0;i<50;i++) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
            //同步代码块
			synchronized(ts) {
				System.out.println(Thread.currentThread().getName()+"买到    票:"+ts.tickets);//输出当前线程所买到的票序
				ts.tickets--;//每售出一张票,总票数-1
			}
		}	
	}

Output result:

 Problem solved successfully.

Next, we use the synchronization method to modify the above code, and we need to change the thread class to implements Runnable

package ThreadSafe;
	//买票线程
public class TicketThread implements Runnable{
	public TicketSystem ts;//售票系统
	//初始化售票系统
	public TicketThread(TicketSystem ts) {
		this.ts = ts;
	}
	public void run() {
		for(int i=0;i<50;i++) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			print();
		}	
	}
	//同步方法
	public synchronized void print() {
		System.out.println(Thread.currentThread().getName()+"买到票:"+ts.tickets);//输出当前线程所买到的票序
		ts.tickets--;//每售出一张票,总票数-1
	}
}
package ThreadSafe;

public class Main {
	public static void main(String[]args) {
		TicketSystem ts = new TicketSystem();//售票系统
		TicketThread t = new TicketThread(ts);//购票线程
		Thread t1 = new Thread(t);
		t1.setName("线程A");
		t1.start();
		Thread t2 = new Thread(t);
		t2.setName("线程B");
		t2.start();
	}
}

                                                                Output result:

 Problem solved successfully.

Guess you like

Origin blog.csdn.net/m0_73249076/article/details/129961944