Java multithreading (three) --- synchronization and deadlock

The origin of the question:

Take train ticket sales as an example. If you want to buy train tickets now, you can go to the train station or go to various online ticketing outlets. However, no matter how many places there are to sell train tickets, the number of train tickets is fixed. All the ticket outlets Must share the same train ticket. If the ticket point is likened to a thread, all threads share a process resource in time.

Implementation of the code:

class MyThread1 implements Runnable{
	private int ticket=5;
	public void run() {
		for(int i=0;i<100;i++) {
			if(ticket>0) {
				System.out.println("卖第"+ticket--+"张票");}}}}
public class TongBu {
	public static void main(String[] args) {
		MyThread1 mThread1=new MyThread1();
		Thread t1=new Thread(mThread1);
		Thread t2=new Thread(mThread1);
		Thread t3=new Thread(mThread1);
		t1.start();
		t2.start();
		t3.start();}}

operation result:
image

But in practical applications, our data is stored in the database, and our user order information is also stored in the database, which means that it takes a certain time delay for us to save the data to the database, here we Simulate the network delay.

Implementation code:

class MyThread1 implements Runnable{
	private int ticket=5;
	public void run() {
		for(int i=0;i<100;i++) {
			if(ticket>0) {
				System.out.println("卖第"+ticket--+"张票");
				try {
					Thread.sleep(500);
				} catch (Exception e) {
					// TODO: handle exception}}}}}
public class TongBu {
	public static void main(String[] args) {
		MyThread1 mThread1=new MyThread1();
		Thread t1=new Thread(mThread1);
		Thread t2=new Thread(mThread1);
		Thread t3=new Thread(mThread1);
		t1.start();
		t2.start();
		t3.start();}}

Let's take a look at the running results:
image

You can see that the number of tickets is sold repeatedly, and there are problems with the program code, which will also cause conflicts among users.

Why is there such a phenomenon?

Here, let's briefly analyze the implementation steps of the operation code?
Insert picture description here

Here we can see that thread 1 takes out the data in the resource, performs a minus one operation, and then puts it back. The reason we repeat the number here is that when thread 1 takes out the resource, thread 2 also takes it out at the same time, for example, thread 1 takes it out. It was 3 before, and the number after thread 1 went out was 3. But because of the network delay, when thread 1 was just taken out and not processed and put back, thread 2 page took out resource 3 at the same time. At this time, thread 1 and thread 2 got the data Both are 3. At this time, thread 1 calculates as 2 and outputs 2, and thread 2 calculates as 2 and outputs 2, so that repeated numbers are generated.

how to solve this problem?

If you want to solve such a problem, you must use synchronization. The so-called synchronization means that multiple operations can only be performed by one thread in the same time period, and other threads must wait for the completion of this thread before continuing, that is, when thread 1 During execution, that is, after thread 1 fetches data, thread 2 cannot operate on resource variables, which is synchronous locking.

image

Synchronize

To solve the synchronization operation problem of resource sharing, you can use the synchronization code block and synchronization method to complete.

Synchronization code block

Code blocks are divided into four types of code blocks:

  • Common code block: It is a code block directly defined in a method.
  • Building block: It is defined directly in the class, and is executed before the construction method, and can be called repeatedly.
  • Static fast: It is declared using the static keyword, which takes precedence over the execution of the building block and is executed only once.
  • Synchronized code block: The code block declared with the synchronized keyword is called a synchronized code block.

Definition format:

synchronize(synchronization object) {

The code that needs to be synchronized and locked;}

Generally, the current object is regarded as the synchronized object, which is represented by this.

public void run() {
		for(int i=0;i<100;i++) {
			synchronized (this) {			
			if(ticket>0) {				
				try {
					Thread.sleep(500);
				} catch (Exception e) {
					// TODO: handle exception
				}
				System.out.println("卖第"+ticket--+"张票");
			}}

The program will be executed step by step, but the speed will be reduced.
Synchronization method

Add a synchronize before the method return value.

The format is synchronize method return value method name (parameter list) {}

Deadlock

Too many programs will cause deadlock

Synchronization is the prerequisite for deadlock. For example, there are two threads. Thread A needs the resources of thread B to execute, and thread B also needs the resources of thread A to execute. It's always waiting for the other party to take out resources, which is called deadlock.

Multithreading and multiprocessing improve the utilization of system resources and increase the processing capacity of the system. However, concurrent execution also brings a new problem-deadlock. The so-called deadlock refers to a deadlock (waiting for each other) caused by multiple threads competing for resources. If there is no external force, these processes will not be able to move forward.

The so-called deadlock refers to a phenomenon in which two or more threads are waiting for each other due to competition for resources during the execution process. If there is no external force, they will not be able to advance.

Below we use an example to illustrate the deadlock phenomenon.

Two people cross the single-plank bridge face to face. Both A and B have already walked a distance on the bridge, that is, occupying the resources of the bridge. If A wants to pass the single-plank bridge, B must exit the bridge to let out the bridge resources, and let A pass, but B No, B still wants to go first, so that both A and B are stuck on the bridge and this is a deadlock.

image

Necessary conditions for deadlock:

Four conditions are indispensable for deadlock generation, which is similar to that polymorphism must be generated on the basis of inheritance.

  • Mutually exclusive conditions: The process requires exclusive control of the allocated resources (such as printers), that is, a certain resource can only be occupied by one process within a period of time. If other processes request resources at this time, the requested process can only wait.
  • Non-deprivation conditions: the resources acquired by the process cannot be forcibly taken away by other processes before they are used up, that is, they can only be released by the process that acquired the resources (only active release, not passive release)
  • Request and retention conditions: The process has retained at least one resource, but has made a new resource request, and the resource is already occupied by other processes. At this time, the requesting process is blocked, but the resources it has acquired will not be released.

Cyclic waiting condition: there is a cyclic waiting chain of process resources, the resources obtained by each process in the chain are requested by the next process in the chain at the same time, and there is a set of processes in a waiting state: p1, p2...pn}, The resource waiting for Pi is occupied by P(i+1) (i=0, 1, …, n-1), and the resource waiting for Pn is occupied by P0, as shown in Figure 1.

Intuitively, the loop waiting condition seems to be the same as the definition of deadlock, but it is not. According to the definition of deadlock, the conditions required to form a waiting loop are more stringent. It requires that the resources that Pi waits for must be satisfied by P(i+1), while the cyclic waiting condition has no such restriction. For example, there are two output devices in the system, P0 occupies one, PK occupies the other, and K does not belong to the set {0, 1, …, n}.

  • Pn waits for an output device. It can be obtained from P0 or from PK. Therefore, although Pn, P0, and some other processes form a circular waiting circle, PK is not in the circle. If PK releases the output device, the circular waiting can be broken, as shown in Figure 2-16. Therefore, cyclic waiting is only a necessary condition for deadlock.

image

How to avoid deadlock?

  • One of the four major conditions that destroy the deadlock
  • Locking sequence (threads lock in a certain order)
  • Locking time limit (a certain time limit is added when the thread tries to acquire the lock, and when the time limit is exceeded, the request for the lock is abandoned and the lock it owns is released)
  • Deadlock detection

Guess you like

Origin blog.csdn.net/qq_44762290/article/details/112379636