Thread synchronization

await 2021-09-15 09:58:34

When two or more threads need to share resources , They need some way to make sure that resources are occupied by only one thread at a time . The process of achieving this is called synchronization (synchronization). As you can see ,Java It provides a unique , Language level support .

The key to synchronization is the tube side ( It's also called semaphore semaphore) The concept of . A pipe is an exclusive lock object , Or mutex (mutex). At a given time , Only one thread can get the pipe . When a thread needs to be locked , It has to go into the tube side . All other threads trying to enter a locked pipe must be suspended until the first thread exits the pipe . These other threads are called wait threads . A thread with a process can enter the same process again if it wants to .

If you use other languages, such as C or C++ Over synchronization is used in , You'll know it's a little weird to use . This is because many languages do not support synchronization themselves . contrary , For synchronous threads , The program must use the operating system source language . Fortunately, Java Synchronization through language elements , Most of the complexity associated with synchronization is eliminated .

You can synchronize code in two ways . Both include synchronized Use of keywords , These two methods are described below . Use the synchronization method Java Synchronization in is simple , Because all objects have their corresponding implicit processes . To enter the tube of an object , It's called being synchronized Methods of keyword modification . When a thread is inside a synchronization method , All attempts to call the method ( Or other synchronization methods ) Other threads of the same instance must wait . In order to exit the tube side , And give up control of the object to other waiting threads , The thread that owns the pipe just needs to return... From the synchronization method .

To understand the need for synchronization , Let's start with a simple example where synchronization should be used but it doesn't work . The following program has three simple classes . First of all Callme, It has a simple way call( ).call( ) The method has a name msg Of String Parameters . This method attempts to print... Within square brackets msg character string . The interesting thing is to call call( ) Print left parentheses and msg After the string , call Thread.sleep(1000), This method pauses the current thread 1 second .

The constructor of the next class Caller, Refer to the Callme An example of and a String, They exist separately target and msg in . The constructor also creates a call to the object run( ) Method . The thread starts immediately .Caller Class run( ) Method passes the parameter msg String call Callme example target Of call( ) Method . Last ,Synch Class is created by Callme A simple example and Caller Start with three instances of with different message strings .

Callme The same instance of is passed to each Caller example . // This program is 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 this program is as follows : Hello[Synchronized[World] ] ]

In this case , By calling sleep( ),call( ) Method allows the execution to switch to another thread . The result is a mixed output of three message strings . In this program , There is no method that prevents three threads from calling the same method of the same object at the same time . This is a competition , Because three threads compete to complete the method . For example sleep( ) Make the effect repeated and obvious . In most cases , Competition is more complex and unpredictable , Because you can't be sure when context switching will happen . This makes the program run normally and make mistakes .

In order to achieve the purpose of the above example , Must have the right to use continuously call( ). in other words , At some point , It must be limited to one thread that can dominate it . So , You just need to call( ) Add the keyword before the definition synchronized, as follows : class Callme {

synchronized void call(String msg) {
...

This prevents the use of... In a thread call( ) When other threads enter call( ). stay synchronized Add to call( ) Before and after , The program output is as follows : [Hello] [Synchronized] [World]

Any time in the case of multithreading , You have one or more methods to manipulate the internal state of an object , All must use synchronized Keyword to prevent state competition . remember , Once the thread enters the instance synchronization method , No other thread can enter the synchronization method of the same instance . However , Other asynchronous methods of this instance can still be called . Synchronous statement Although creating synchronization methods inside the created classes is a simple and effective way to get synchronization , But it doesn't work at all times . The reason for this , Please follow me . Suppose you want to get synchronous access to class objects that are not designed for multithreaded access , That is to say , This class does not use synchronized Method . and , It's not you , It's created by a third party , You can't get its source code . such , You can't add... Before the relevant method synchronized Modifier . How to synchronize an object of this class ? Very lucky , The solution is simple : You just need to put the call to the method defined by this class into a synchronized It's OK in the block .

Here is synchronized The common form of a statement : synchronized(object) {

// statements to be synchronized

}

among ,object Is a reference to the synchronized object . If all you want to synchronize is a statement , Then you don't need curly braces . A synchronization block ensures that object The member method is called only when the current thread successfully enters object Occurs after the tube pass .

The following is a modified version of the previous program , stay run( ) A synchronization block is used in the method : // This program uses a synchronized block. 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();
}
// 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 ,call( ) The method has not been synchronized modification . and synchronized Is in Caller Class run( ) Method . This can get the same correct result in the above example , Because each thread waits for the previous thread to end before running . When two or more threads need to share resources , They need some way to make sure that resources are occupied by only one thread at a time . The process of achieving this is called synchronization (synchronization). As you can see ,Java It provides a unique , Language level support .

The key to synchronization is the tube side ( It's also called semaphore semaphore) The concept of . A pipe is an exclusive lock object , Or mutex (mutex). At a given time , Only one thread can get the pipe . When a thread needs to be locked , It has to go into the tube side . All other threads trying to enter a locked pipe must be suspended until the first thread exits the pipe . These other threads are called wait threads . A thread with a process can enter the same process again if it wants to .

If you use other languages, such as C or C++ Over synchronization is used in , You'll know it's a little weird to use . This is because many languages do not support synchronization themselves . contrary , For synchronous threads , The program must use the operating system source language . Fortunately, Java Synchronization through language elements , Most of the complexity associated with synchronization is eliminated .

You can synchronize code in two ways . Both include synchronized Use of keywords , These two methods are described below . Use the synchronization method Java Synchronization in is simple , Because all objects have their corresponding implicit processes . To enter the tube of an object , It's called being synchronized Methods of keyword modification . When a thread is inside a synchronization method , All attempts to call the method ( Or other synchronization methods ) Other threads of the same instance must wait . In order to exit the tube side , And give up control of the object to other waiting threads , The thread that owns the pipe just needs to return... From the synchronization method .

To understand the need for synchronization , Let's start with a simple example where synchronization should be used but it doesn't work . The following program has three simple classes . First of all Callme, It has a simple way call( ).call( ) The method has a name msg Of String Parameters . This method attempts to print... Within square brackets msg character string . The interesting thing is to call call( ) Print left parentheses and msg After the string , call Thread.sleep(1000), This method pauses the current thread 1 second .

The constructor of the next class Caller, Refer to the Callme An example of and a String, They exist separately target and msg in . The constructor also creates a call to the object run( ) Method . The thread starts immediately .Caller Class run( ) Method passes the parameter msg String call Callme example target Of call( ) Method . Last ,Synch Class is created by Callme A simple example and Caller Start with three instances of with different message strings .

Callme The same instance of is passed to each Caller example . // This program is 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 this program is as follows : Hello[Synchronized[World] ] ]

In this case , By calling sleep( ),call( ) Method allows the execution to switch to another thread . The result is a mixed output of three message strings . In this program , There is no method that prevents three threads from calling the same method of the same object at the same time . This is a competition , Because three threads compete to complete the method . For example sleep( ) Make the effect repeated and obvious . In most cases , Competition is more complex and unpredictable , Because you can't be sure when context switching will happen . This makes the program run normally and make mistakes .

In order to achieve the purpose of the above example , Must have the right to use continuously call( ). in other words , At some point , It must be limited to one thread that can dominate it . So , You just need to call( ) Add the keyword before the definition synchronized, as follows : class Callme {

synchronized void call(String msg) {
...

This prevents the use of... In a thread call( ) When other threads enter call( ). stay synchronized Add to call( ) Before and after , The program output is as follows : [Hello] [Synchronized] [World]

Any time in the case of multithreading , You have one or more methods to manipulate the internal state of an object , All must use synchronized Keyword to prevent state competition . remember , Once the thread enters the instance synchronization method , No other thread can enter the synchronization method of the same instance . However , Other asynchronous methods of this instance can still be called . Synchronous statement Although creating synchronization methods inside the created classes is a simple and effective way to get synchronization , But it doesn't work at all times . The reason for this , Please follow me . Suppose you want to get synchronous access to class objects that are not designed for multithreaded access , That is to say , This class does not use synchronized Method . and , It's not you , It's created by a third party , You can't get its source code . such , You can't add... Before the relevant method synchronized Modifier . How to synchronize an object of this class ? Very lucky , The solution is simple : You just need to put the call to the method defined by this class into a synchronized It's OK in the block .

Here is synchronized The common form of a statement : synchronized(object) {

// statements to be synchronized

}

among ,object Is a reference to the synchronized object . If all you want to synchronize is a statement , Then you don't need curly braces . A synchronization block ensures that object The member method is called only when the current thread successfully enters object Occurs after the tube pass .

The following is a modified version of the previous program , stay run( ) A synchronization block is used in the method : // This program uses a synchronized block. 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();
}
// 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 ,call( ) The method has not been synchronized modification . and synchronized Is in Caller Class run( ) Method . This can get the same correct result in the above example , Because each thread waits for the previous thread to end before running .

This article altogether 2810 Number of words , Average reading time ≈ 8 minute

Participation of this paper Tencent cloud media sharing plan , You are welcome to join us , share .

Please bring the original link to reprint ,thank
Similar articles

2021-09-15