When two or more two threads need to share resources, they need some way to determine that the resource is occupied by only one thread at a moment. The process to achieve this is called Synchronization (synchronization). As you can see, Java provides unique, language-level support for this.
The key to synchronization is the concept of enhancement (also called Semaphore semaphore). Enhancement is a mutex exclusive lock object, or mutex (mutex). At a given time, only one thread can get a pipe. When a thread needs to be locked, it must go into the pipe. All other threads attempting to enter a locked enhancement must hang until the first thread exits the pipe. These other threads are called waiting for a pipe. A thread that has a pipe can enter the same enhancement again if you wish.
If you've used synchronization in other languages such as C or C + +, you'll know it's a bit tricky to use. This is because many languages themselves do not support synchronization. Instead, for a synchronization thread, the program must take advantage of the operating system source language. Fortunately, Java is synchronized with language elements, and most of the synchronization-related complexities are eliminated.
You can synchronize your code in two ways. Both of these include the use of synchronized keywords, which are described below respectively.
Using the synchronization method
Synchronization in Java is simple, because all objects have implicit threads that correspond to them. The process of entering an object is called by the method that is modified by the Synchronized keyword. When a thread is inside a synchronous method, all other threads that attempt to invoke the same instance of the method (or other synchronization methods) must wait. To exit the pipe and discard control of the object to other waiting threads, the thread that owns the pipe only needs to be returned from the synchronization method.
To understand the need for synchronization, let's start with a simple example that should be used without synchronization. The following program has three simple classes. The first is CallMe, which has a simple method of call (). The call () method has a string parameter named Msg. The method attempts to print the MSG string inside the square brackets. The interesting thing is to call Thread.Sleep (1000) after calling call () to print the opening parenthesis and the MSG string, which causes the current thread to pause for 1 seconds.
The constructor for the next class, caller, references an instance of CallMe and a string, which are respectively in Target and MSG. The constructor also creates a new thread that invokes the run () method of the object. The thread starts immediately. The run () method of the caller class invokes the call () method of the CallMe instance target through the parameter msg string. Finally, the Synch class starts with a simple instance of creating a CallMe and three instances of caller with different message strings.
The same instance of CallMe is passed to each caller instance.
This program was not synchronized.
Class Callme {
void Call (String msg) {
System.out.print ("[" + msg);
try {
Thread.Sleep (1000);
} catch (Interruptedexception e) {
System.out.println ("interrupted");
}
System.out.println ("]");
}
}
Class Caller implements Runnable {
String msg;
Callme Target;
Thread T;
Public Caller (Callme Targ, String s) {
target = Targ;
msg = s;
t = new Thread (this);
T.start ();
}
public void Run () {
Target.call (msg);
}
}
Class Synch {
public static void Main (String args[]) {
Callme target = new Callme ();
Caller ob1 = new Caller (target, "Hello");
Caller ob2 = new Caller (target, "Synchronized");
Caller ob3 = new Caller (Target, "world");
Wait for threads to end
try {
Ob1.t.join ();
Ob2.t.join ();
Ob3.t.join ();
} catch (Interruptedexception e) {
System.out.println ("interrupted");
}
}
}
The output of the program is as follows:
Hello[synchronized[world]
]
]
In this example, by calling sleep (), the call () method allows the execution to transition to another thread. The result is a mixed output of three message strings. There is a method in the program that does not prevent three threads from calling the same method at the same time. This is a competition because three threads are contending for the completion method. The example uses sleep () to make the effect repetitive and obvious. In most cases, competition is more complex and unpredictable because you cannot determine when context conversions will occur. This causes the program to run normally and sometimes error.
To achieve the purpose of the above example, you must have the right to use call () consecutively. That is, at some point, you have to limit only one thread to dictate it. To do this, you simply precede the call () definition with the keyword synchronized, as follows:
Class Callme {
synchronized void call (String msg) {
...
This prevents other threads from entering call () when one thread is using call (). After synchronized is added to call (), the program output is as follows:
[Hello]
[Synchronized]
[World]
Any time you have a method or multiple methods to manipulate an object's internal state in a multithreaded situation, you must use the Synchronized keyword to prevent the state from competing. Remember that once a thread enters the instance's synchronization method, no other thread can enter the same instance of the synchronization method. However, other unsynchronized methods of the instance can still be called.
Synchronization statements
Although creating a synchronization method inside a class created is a simple and efficient way to get synchronized, it is not valid at all times. The reason for this, please follow the thinking. Suppose you want to obtain synchronous access to a class object that is not designed for multithreaded access, that is, the class does not use the Synchronized method. Moreover, the class is not yourself, but a third party created, and you cannot get its source code. This way, you cannot add synchronized modifiers before the relevant method. How can I synchronize an object of this class? Fortunately, the solution is simple: you simply put the call to the method defined by this class in a synchronized block.
The following is the normal form of the synchronized statement:
Synchronized (object) {
Statements to be synchronized
}
Where object is a reference to the synchronized objects. If you want to synchronize only one statement, then no curly braces are required. A synchronization block ensures that a call to an object member method occurs only after the current thread has successfully entered an object pipe.
The following is a modified version of the previous program, using a synchronization block within the run () method:
This program uses a synchronized block.
Class Callme {
void Call (String msg) {
System.out.print ("[" + msg);
try {
Thread.Sleep (1000);
} catch (Interruptedexception e quqiongyule2.com) {
System.out.println ("interrupted");
}
System.out.println ("]");
}
}
Class Caller implements Runnable {
String msg;
Callme Target;
Thread T;
Public Caller (Callme Targ, String s) {
target = Targ;
msg = s;
t = new Thread (this);
T.start ();
}
Synchronize calls to call ()
public void Run () {
Synchronized (target) {//synchronized block
Target.call (msg);
}
}
}
Class Synch1 {
public static void Main (String args[]) {
Callme target = new Callme ();
Caller ob1 = new Caller (target, "Hello");
Caller ob2 = new Caller (target, "Synchronized");
Caller ob3 = new Caller (Target, "world");
Wait for threads to end
try {
Ob1.t.join ();
Ob2.t.join ();
Ob3.t.join ();
} catch (Interruptedexception e) {
System.out.println ("interrupted");
}
}
}
Here, the call () method is not modified by synchronized. The synchronized is declared in the run () method of the caller class. This gives the same correct result in the previous example, because each thread waits for the previous thread to end before it runs.
Seven. Multithreaded programming 8. Thread synchronization