Multithreaded programming brings a lot of convenience to program development, but it also brings some problems, which are the problems that must be dealt with in the process of program Development.
The core of these issues is how to ensure access security when multiple threads access a resource at the same time, such as variables, files, and so On. In multithreaded programming, this resource, which is accessed concurrently by multiple threads, is called a critical resource.
The following is a simple example that demonstrates the problems that occur when multiple threads access critical resources. In this example, an object of two thread class Datathread is started, which outputs the value of the variable n every 200 milliseconds and reduces the value of N by 1. The value of the variable n is stored in the data class that simulates the critical resource, and the core of the example is that all two thread classes use the same data class object, so that the object of the data class is a critical resource.
The sample code is as Follows:
package syn1; /** * Class of the simulated critical resource */ public class Data { public int n; public Data () {n = 60; }}
package syn1; /** * Test multi-threaded access problems */ public class TestMulThread1 { public static void main (string[] Args) { Data data = new data (); Datathread D1 = new datathread (data, "thread 1" ); Datathread d2 = new datathread (data, "thread 2" ); }}
packagesyn1;/*** Threads that Access data*/ public classDatathreadextendsThread {data data; String name; publicdatathread (Data data,string Name) { this. data =data; this. Name =name; Start (); } public voidRun () {Try{ for(inti = 0;i < 10;i++) {System.out.println (name+ ":" +data.n); DATA.N--; Thread.Sleep (200); } }Catch(Exception E) {} }}
At run time, because the program runs differently under different circumstances, one of the execution results of the program Is:
Thread 1:60 thread 2:thread 2: 1thread 2: 1 threads, thread of thread . thread 2:thread 1:thread 2:thread 1: thread 2:1 thread:-thread 2: thread 1: 2thread 1: 1 thread 2: 42 thread
View Code
From the execution results, the first output of 60 is understandable, because the thread in the execution of the first output variable value, this time the value of the variable n is still the initial value of 60, and the subsequent output is more troublesome, at the beginning of the two variables to maintain a consistent output, instead of outputting the contents of each value of n sequentially, and to the end, thread 2 outputs 47 of this median Value.
The reason for this is simple: thread 1 changed the value of the variable n, there is no time to output, the value of the variable n is changed by thread 2, so the output of the output is jumping, and occasionally appear continuous.
This problem is also relatively easy to accept, because the most basic multi-threaded program, the system only guarantees that the thread executes simultaneously, as to which one executes, which executes, or the execution of a thread executes in half, the execution of the CPU is given to another thread, so that the execution order of the thread is random and Uncontrolled. So the result will appear Above.
Such results are unacceptable in many practical applications, such as banking applications, where two of people take one account at a time, one using a passbook, and one using a card, so that the amount of access to the account can be problematic. Or in the ticketing system, if that's the case, There's a ticket for the same seat, and some seats are UNSOLD.
In multithreaded programming, This is a typical critical resource problem, the most basic solution to this problem, the simplest idea is to use the Synchronization keyword Synchronized.
The Synchronized keyword is a modifier that can be used to decorate a method or block of code that, for the same object (not a different object of a class), must be executed sequentially when multiple threads call the method or block of code at the same time, that is, If two or more than two threads execute the code at the same time, if one thread has already started executing the code, the other thread must wait for the thread to finish executing the code before it can begin Execution. Just like in the Bank's counter business, the salesperson is the object, each customer is like a thread, when a customer starts processing, the other customers must wait, in time the processing of the customer in the process of receiving a call (analogy to this thread freed up CPU time, and in the blocking state), Other threads can only wait.
Use the Synchronized keyword to modify the following code:
packagesyn2;/*** Simulation of critical resource classes*/ public classData2 { public intn; publicData2 () {n= 60; } public synchronized voidaction (String Name) {System.out.println (name+ ":" +n); N--; }}
package syn2; /** * Test multi-threaded access problems */ public class TestMulThread2 { public static void main (string[] Args) { Data2 data = new Data2 (); Data2thread D1 = new data2thread (data, "thread 1" ); Data2thread d2 = new data2thread (data, "thread 2" ); }}
packagesyn2;/*** Threads that Access data*/ public classData2threadextendsThread {Data2 data; String name; publicdata2thread (Data2 data,string Name) { this. data =data; this. Name =name; Start (); } public voidRun () {Try{ for(inti = 0;i < 10;i++) {data.action (name); Thread.Sleep (200); } }Catch(Exception E) {} }}
The result of the sample code is different, and one of the execution results is:
Thread 1:60 thread 2:thread 2: 1thread 2: 1 thread of the Thread. thread 2:thread 1:thread 2:thread 1:thread 1:thread 2: thread 2: thread 1:thread 2:thread 1:thread 2:thread 1:41
View Code
In this example, the code that prints the variable n and the variable n change code form a special method action and use the modifier synchronized to modify the method, that is, for a Data2 object, no matter how many threads call the action method at the same time, Only one thread will be able to execute the method after the method has been completely executed by the other line friend. This is equivalent to a thread executing to the Object's synchronized method, the object is added a lock, lock the object, the other thread when the method is called, the lock will continue to wait.
If this example does not help you understand how to solve the problem of multithreading, then look at a more practical example-the toilet problem.
For example, the toilet of the train compartment, in order to simple, here only simulates a bathroom, this bathroom will be used by many people at the same time, in the actual use, when a person enters the bathroom will lock the bathroom, wait out when the door opened, the next person in the door lock, If there is a person in the bathroom inside the other people find the door is locked can only wait Outside. From a programmatic point of view, everyone here can be regarded as a thread object, and this toilet object is accessed by multiple threads, is a critical resource, when a thread is actually used, the critical resource is locked with synchronized key, and when the end, the lock is Released. The implementation code is as Follows:
packagesyn3;/*** Test Class*/ public classTesthuman { public Static voidmain (string[] Args) {toilet t=NewToilet ();//Bathroom ObjectsHuman H1 =NewHuman ("1", t); Human H2=NewHuman ("2", t); Human H3=NewHuman ("3", t); }}
packagesyn3;/*** Human threading class, demonstrating mutex*/ public classHumanextendsThread {toilet t; String name; publicHuman (String name,toilet t) { this. Name =name; this. T =t; Start (); //Start Thread } public voidRun () {//Access to The bathroomT.enter (name); }}
packagesyn3;/*** bathroom, Mutex demo*/ public classToilet { public synchronized voidEnter (String name) {System.out.println (name+ "has entered! "); Try{thread.sleep (2000); }Catch(Exception e) {} System.out.println (name+ "leave! "); }}
The result of the example is a different number of executions:
1 has entered! 1 leave! 3 has entered! 3 leave! 2 has entered! 2 leave!
View Code
In this sample code, the toilet class represents the bathroom class, the human class emulator, the thread class in the example, and the Testhuman class is the test class that is used to start the THREAD. In testhuman, you first create an object t of type toilet and pass that object to the thread object that you create later, so that subsequent thread objects use the same toilet object, which becomes a critical resource. The following creates three thread objects of type human, each with its own name, a parameter that simulates 3 threads, in each thread object, just the Enter method in the Call object t, simulates the move into the toilet, and in the Enter method, the input thread that calls the method enters when it enters, Then a delay of 2 seconds, the output of the thread leaves, and then a subsequent thread enters, until three threads have completed the Enter method then the program ENDS.
In this example, the Enter method of the object T of the same toilet class is decorated with the synchronized modifier, and when multiple threads call the method at the same time, if a thread enters the inside of the Enter method, the object T is locked, Until the end of the Enter method to release the lock on the object, in this way no matter how many human type of thread, for the same object t, at any time only one thread to execute the Enter method, this is the first way to solve multithreading problem-mutual exclusion Principle.
Java multi-threading problem and handling (i) "go"