[untitled] thread synchronization required for school recruitment interview (detailed solution)

Posted by soccerstar_23 on Fri, 04 Feb 2022 03:33:30 +0100

Multithreading overview

1, The concept of multithreading

Multithreading means that a program contains multiple execution units, that is, multiple different threads can be run simultaneously to perform different tasks in a program, that is, a single program is allowed to create multiple parallel threads.

2, Using multithreading

  1. The program needs to perform two or more tasks at the same time
  2. When the program needs to realize some tasks that need to wait, such as user input, file reading and writing operation, network operation, search, etc. For example, when the user input part occupies the CPU, if there is no input, it is impossible to make this part occupy the CPU all the time. At this time, it will make other threads run on the CPU
  3. When you need some programs running in the background

2, Advantages and disadvantages of multithreading (focusing on disadvantages)

advantage:

  1. Improve program response

  2. Improve CPU utilization

  3. Improve the program structure, divide complex tasks into pairs of threads and run independently

Disadvantages:

  1. Threads are also programs, so threads need to occupy memory. The more threads, the more memory they occupy

The first point is easy to improve. If we continuously improve the performance of the computer, we can improve the problem of memory occupation

  1. Multithreading requires coordination and management, so CPU time is required to track threads

  2. The access of threads to shared resources will affect each other, and the problem of competing for shared resources must be solved (the most important problem)

For example, when we buy movie tickets during the Spring Festival, 30 people in the class buy the same show in the same cinema. As a shared resource, Zhang San wants to buy No. 8, row 7. It happens that Li Si also wants to buy No. 8, row 7. When Zhang San and Li Si buy tickets, they are equivalent to creating two threads (multi threads). If they are not controlled, they compete to share resources. Zhang San has just bought tickets, and the ticket counter enters the blocking state before it can be reduced by one. While Li Si still sees the ticket, he also bought it. There will be an accident at this time. This is the biggest problem of multithreading.

3, Parallelism and concurrency

To understand parallelism and concurrency, we should pay attention to two words: the same time and a time period

Parallelism: parallelism is when multiple things happen at the same time. For example: multiple athletes start at the same time when they hear the gunshot, and multiple CPU s start to execute multiple threads at the same time

Concurrency: concurrency refers to the occurrence of multiple events in a time period. These events are very compact in time, but they still have sequence. For example, a single core CPU can only execute one thread at a time, but we chat with QQ while playing music. It seems to happen at the same time, but it is actually constantly exchanged. Because the time for these threads to get on and off the processor is very short, in our opinion, they occur at the same time, which is concurrency.

Thread synchronization

1, Multithread synchronization

***Conflicts may arise when multiple threads read and write the same shared resource at the same time (the example of buying movie tickets above). Therefore, the "synchronization" mechanism of threads is introduced, that is, there should be first come, first served between threads;

Synchronization is queue + lock:

  1. Several threads should queue up to operate the shared resources one by one, rather than operate at the same time

  2. In order to ensure the correctness of data being accessed in the method, lock mechanism is added during access

Two, simulation ticket buying as an example to explain thread synchronization.

There are two windows to sell tickets. The current total number of tickets is 10, which are realized by inheriting Thread and realizing Runnable respectively:

1, Inherit Thread mode

Create package: package com ffyc. javathread. demo6;

Create class: TicketThread class

Create class: Test class

public class TicketThread extends Thread{
    int num = 10; //There are 10 tickets set
    static Object obj = new Object();
    @Override
    public void run(){
        while(true){
            
            synchronized(obj) {  //Entering the synchronization code block will change the lock state in the object header to yoke -- >
                if (num > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "Got a ticket:" + num);

                    num--;
                } else {
                    break;
                }
            }  //The lock will be released automatically after the synchronization code block is executed
        }
    }

}
/*
synchronized(Synchronization objects) synchronization objects can be objects of any class, but they can only be unique and have only one copy
 In this case, we can't use this because we create two thread objects. Which thread accesses, this represents which thread
 There is an area in the object called the object header, and there is a record of lock status in the object header
*/

Let me explain the above code in detail. I can't understand it. It's impossible!

public class TicketThread extends Thread{
    int num = 10;//num indicates that the ticket is a member of the class, and the attribute = = the variable of the whole
    
    @Override
    public void run(){  
        /*Thread creation according to the previous article, whether inheriting the thread or implementing the Runnable interface, it is necessary to rewrite the run() method. The method body of the run() method writes the tasks to be executed by the thread*/
        
    }
    
}    

Just rewrite the outline of the run() method first. See it after the specific implementation

***We need to create two windows (threads) required by the topic in the main method

Create package: package com ffyc. javathread. demo6;

Create class: Test class

package com.ffyc.javathread.demo6;

public class Test{
    public static void main(String [] args){
        
        TicketThread th1 = new TicketThread();  
        /*A thread object is created, that is, a thread is created*/
        th1.setName("Window 1"); //The party that names the Thread in the Thread: setName()
        th1.start();
        /* Start the thread, that is -- > enter the ready state and wait for CPU scheduling*/
        
        //Create a second thread
        TicketThread th2 = new TicketThread();
        th2.setName("Window 2");
        th2.start();
        
        
    }
}

Next, let's implement the run() method:

@Override
    public void run(){  
        while(true){
            if(num>0){
                //Ticket buying method
                System.out.println(Thread.currentThread().getName()+"Buy a ticket:"+mun);
                num--;
            }else{
                break;//When the number of mun votes is less than or equal to 0, there are no votes, and the break ends
            }
                
        }
        
    }

Now, the integration is:

package com.ffyc.javathread.demo6;
public class TicketThread extends Thread{
    int num = 10;//num indicates that the ticket is a member of the class, and the attribute = = the variable of the whole
    
    @Override
    public void run(){  
        /*Thread creation according to the previous article, whether inheriting the thread or implementing the Runnable interface, it is necessary to rewrite the run() method. The method body of the run() method writes the tasks to be executed by the thread*/
         while(true){
            if(num>0){
                //Ticket buying method
                System.out.println(Thread.currentThread().getName()+"Buy a ticket:"+mun);
                //The sleep() method requires a try/catch exception
                //The sleep() method is thread sleep. Parameter 100 refers to sleep for 100ms, that is, let the currently executing thread sleep (suspend execution)
                try{
                Thread.sleep(100);
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
                
                num--;
            }else{
                break;//When the number of mun votes is less than or equal to 0, there are no votes, and the break ends
            }
                
        }
        
    }
    
}    


package com.ffyc.javathread.demo6;
public class Test{
    public static void main(String [] args){
        
        TicketThread th1 = new TicketThread();  
        /*A thread object is created, that is, a thread is created*/
        th1.setName("Window 1"); //The party that names the Thread in the Thread: setName()
        th1.start();
        /* Start the thread, that is -- > enter the ready state and wait for CPU scheduling*/
        
        //Create a second thread
        TicketThread th2 = new TicketThread();
        th2.setName("Window 2");
        th2.start();
        
        
    }
}

The above ticket selling program will make an error. It is not an error in the compilation period. It is an example of buying movie tickets mentioned above when the program is running: window 1 sold the ticket No. 8 in row 7, and window 2 also sold the ticket.

At the same time, I bought the 10th ticket and the 8th ticket... A total of 10 tickets but sold 12.

The problem of multithreading can be solved by queuing + locking, that is, thread synchronization mechanism.

Two methods of locking (first, lock the code block and lock the method. See the next article)
  1. Lock with the synchronized keyword

You can lock methods or code blocks with synchronized:

(1) Lock code blocks:

package com.ffyc.javathread.demo6;
public class TicketThread extends Thread{
    int num = 10;//num indicates that the ticket is a member of the class, and the attribute = = the variable of the whole
    
    Object obj = new Object();
    
    @Override
    public void run(){  
        /*Thread creation according to the previous article, whether inheriting the thread or implementing the Runnable interface, it is necessary to rewrite the run() method. The method body of the run() method writes the tasks to be executed by the thread*/
         while(true){
            
             
             synchronized(obj){
            	if(num>0){
                	//Ticket buying method
                	System.out.println(Thread.currentThread().getName()+"Buy a ticket:"+mun);
                	//The sleep() method requires a try/catch exception
                //The sleep() method is thread sleep. Parameter 100 refers to sleep for 100ms, that is, let the currently executing thread sleep (suspend execution)
                	try{
                		Thread.sleep(100);
                	}catch(InterruptedException e){
                    	e.printStackTrace();
                	}
                
                	num--;
            		}else{
                		break;//When the number of mun votes is less than or equal to 0, there are no votes, and the break ends
            		}
            }
                
        }
        
    }
    
}    

Synchronization objects in synchronized can be objects of any class, but they can only be unique and have only one copy.

To understand how to lock the synchronized keyword, you need to understand the underlying layer of the object:

In fact, there is an area in the Object called the Object header, which contains a record of lock status. We created an Object object in the TicketThread class. When one of the two threads enters the lock, the lock status of the obj Object will mark that there are threads in the lock. At this time, other threads cannot enter until the synchronized(obj) {} is executed and the flag bit is released. It is safe to allow only one thread at a time.

This cannot be used in this case, because we have created two thread objects (th1 and th2). When accessing the code in the lock: which thread accesses, this indicates which thread's object. Two threads have two this objects, which are not unique, so both can enter the lock.

The following are the running results:

See the next article on thread synchronization~

Topics: Java Interview