当前位置:网站首页>Ten minutes will take you in-depth understanding of multithreading - multithreaded teamwork: synchronous control
Ten minutes will take you in-depth understanding of multithreading - multithreaded teamwork: synchronous control
2022-07-02 02:31:00 【Peach blossom key God】
Multithreaded teamwork : Synchronous control
Synchronization control is an essential means for concurrent programs . Previously introduced keywords synchronized Is one of the simplest control methods , It determines whether a thread can access critical resources . meanwhile ,Object.wait() Methods and Object.notify) Method plays the role of thread waiting and notification . These tools play an important role in realizing complex multi-threaded cooperation . Next, we will first introduce keywords synchronized、Object.wait() Methods and Object.notify() A substitute for the method ( Or an enhanced version )—— Reentrant lock .
One 、 keyword synchronized Functional extension of : Reentrant lock
- Reentry locks can completely replace keywords synchronized. stay JDK
5.0 In an earlier version , Reentry locks perform much better than keywords synchronized, But from JDK 6.0 Start ,JDK In keywords synchronized A lot of optimization has been done on , So the performance gap between the two is not big . - Reentry lock use java.util.concurrent.locks.ReentrantLock Class to achieve . Here's a simple example of using reentry locks .
public class ReenterLock implements Runnable{
public static ReentrantLock lock=new ReentrantLock();
public static int i=0;
@override
public void run(){
for(int j=0;j<10000000;j++){
lock.lock();
try{
i++;}finally{
lock.unlock();
}
}
}
public static void main (String[] args) throws
InterruptedException {
ReenterLock tl=new ReenterLock();
Thread t1=new Thread (tl);
Thread t2=new Thread(tl);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}}
- Above code 7~12 Row uses reentry locks to protect critical area resources i, Make sure that multithreading is correct for i Security of operation . As you can see from this code , With keywords synchronized comparison , The re-entry operation is displayed . Developers must manually specify when to lock , When to release the lock . That's why , Reentry locks are much more flexible than keywords synchronized. But here's the thing , When you exit the critical zone , Remember to release the lock ( Code No. 11 That's ok ), otherwise , Other threads have no chance to access the critical section again .
- You may be surprised by the name of the reentry lock . Why should locks be added “ Reentrant ” Two words? ? From the naming of classes ,Re-
Entrant-Lock Reentry lock is very appropriate . That's why it's called that , It's because the lock can be repeatedly entered . Of course , The repetition here is limited to one thread . The first part of the above code 7~12 That's ok , It can be written in the following form :
lock.lock();lock.lock();try{
i++;}finally{
lock. unlock();lock.unlock();
}
- under these circumstances , It is allowed for a thread to acquire the same lock twice in a row . If this is not allowed , So the same thread is in the 2 The next time you get the lock , Will have a deadlock with myself . The program will “ stuck ” In the 2 In the process of applying for the lock . But it should be noted that , If the same thread gets a lock more than once , So when you release the lock , You have to release the same number of times . If you release the lock more times , Then you get a java.lang.IllegalMonitorStateException abnormal , conversely , If the lock is released less times , So it's equivalent that the thread still holds the lock , therefore , Other threads can't get into the critical area .
- In addition to the flexibility in use , The reentry lock also provides some advanced functions . such as , Reentry locks can provide interrupt handling capabilities .
One 、 Interrupt response
- For keywords synchronized Come on , If a thread is waiting for a lock , So there are only two cases , Either it gets the lock and continues to execute , Or it just keeps waiting . And use reentry locks , It offers another possibility , That is, threads can be interrupted . In the process of waiting for the lock , The program can cancel the lock request as needed . Sometimes , It's very necessary to do this . such as , You and your friends have an appointment to play ball , If you've been waiting for half an hour, your friend hasn't arrived yet , You suddenly get a call , Because of a sudden situation , Friends can't come as promised , So you must have come back to your house in a bad mood . Interrupts provide a similar mechanism . If a thread is waiting for a lock , Then it can still receive a notice , Told not to wait , You can stop working . This situation is helpful in dealing with deadlocks .
- The following code creates a deadlock , But thanks to the lock break , We can easily solve this deadlock .
public class IntLock implements Runnable{
public static ReentrantLock lockl = new ReentrantLock();public static ReentrantLock lock2 = new ReentrantLock();int lock;
/** * Control the locking sequence , Easy to construct deadlock *param lock */
public IntLock(int lock){
this.lock = lock;
}
@override
public void run(){
try {
if (lock == 1){
lock1. lockInterruptibly();try{
Thread.sleep(500);
}catch (InterruptedException e){
1lock2. lockInterruptiblyO);
}else{
lock2 . lockInterruptibly();try{
Thread.sleep (500);
}catch (InterruptedException e){
}lock1. lockInterruptiblyO);
] catch (InterruptedException e){
e.printStackTrace(;
]finally{
if(lock1.isHeldByCurrentThread ())
lockl.unlock ();
if (lock2.isHeldByCurrentThread()
lock2.unlock(;
System.out.println (Thread.currentThread ().getId()+": Thread to exit ");
public static void main(String[] args) throws InterruptedException{
IntLock r1 = new IntLock (1);
IntLock r2= new IntLock(2);Thread tl = new Thread (r1) ;Thread t2 = new Thread(r2);t1.start();t2.start();
Thread.sleep(1000);// Interrupt one of the threads
t2.interrupt ();
}}
- Threads t1 and
t2 After starting ,t1 Occupy first lock1, Reoccupation lock2;t2 Occupy first lock2, The request again lock1. therefore , Easy to form t1 and t2 Waiting for each other . ad locum , A request for a lock , Unified use lockInterruptibly( Method . This is a lock application action that can respond to an interrupt , In the process of waiting for the lock , Can respond to interruptions . - In the code section 47 That's ok , The main thread main
In a dormant state , here , These two threads are in a deadlock state . In the code section 49 That's ok , because t2 Thread interrupted , so t2 Will give up on lock1 Application for , At the same time release what has been obtained lock2. This operation leads to t1 The thread can get lock2 And carry on with it . - Execute the above code , Will output :
java.lang. InterruptedException
at java.util.concurrent. locks.AbstractQueuedSynchronizer.doAcquireInterruptibly (AbstractQueuedSynchronizer.java:898)
at java.util.concurrent. locks. AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
at java.util.concurrent. locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
at geym.conc.ch3.synctrl.IntLock. run (IntLock.java: 31)at java.lang. Thread.run(Thread.java:745)
9: Thread to exit
8: Thread to exit
- You can see , Two threads both exit after interruption , But the only thing that really gets the job done is tl, and t2 The thread abandons its task and exits directly , Release resources .
Two 、 Lock application waiting time
- Besides waiting for external notification , There is another way to avoid deadlocks , It's just waiting for time . Let's still ask friends to play ball , If a friend doesn't come , And he couldn't be reached , So waiting for 1 To 2 After one hour , I think most people will be disappointed to leave . The same is true for threads . Usually , We can't tell why a thread can't get a lock . Maybe it's a deadlock , Maybe it's because of hunger . If given a waiting time , Let the thread automatically give up , So it makes sense for the system . We can use tryLock() Method to wait for a limited time .
- The following code shows the use of time limited wait lock .
public class TimeLock implements Runnable{
public static ReentrantLock lock=new ReentrantLock();@Override
public void run(){
try{
if(lock.tryLock (5,TimeUnit.SECONDS))
Thread.sleep(6000);
}else{
System.out.println ("get lock failed");
}catch (InterruptedException e){
e.printstackTrace();
}finally{
if (lock.isHeldByCurrentThread0) lock.unlock();}
public static void main(String[] args){
TimeLock tl=new TimeLock();
Thread tl=new Thread(tl);Thread t2=new Thread(tl);t1.start();
t2.start();
}}
- ad locum ,tryLock() Method accepts two parameters , One indicates the waiting time , The other is the unit of time . The unit here is set to seconds , The length of 5, Indicates that the thread is waiting at most in this lock request 5 second . If exceeded 5 Seconds have not been locked yet , It will return false. If you succeed in getting the lock , Then return to true.
- In this case , Because the thread that occupies the lock holds the lock for as long as 6 second , So another thread cannot be in 5 Seconds of waiting time to acquire the lock , So the request for a lock fails .
- ReentrantLock.tryLock() Methods can also be run without parameters . under these circumstances , The current thread will try to acquire the lock , If the lock is not occupied by another thread , Then the lock application will succeed , And return immediately true. If the lock is occupied by another thread , The current thread will not wait , It's about going back to false. This pattern does not cause threads to wait , So there is no deadlock . Here's how to use it :
public class TryLock implements Runnable{
public static ReentrantLock lock1 - new ReentrantLock (;public static ReentrantLock lock2 = new ReentrantLock(;int lock;
public TeyLock (int lock){
this.lock = lock;
@override
public void run ( {
if(1ock -- 1){
while (true) [
if(lockl.tryLock0{
tryf
try {
Thread.sleep (500);
}catch (InterruptedException e)[)
if (lock2.tryLock()){
try{
System.out.println/Thread.currentThread()
.getId( +":Ny Job done"];
return;
}finally{
lock2.unlock() ;
}}}
finally {
lock1.unlock();
}
} else{
while (true) {
if(lock2.tryLock()){
try {
try {
Thread.sleep(500);
] catch (InterruptedException e){
if( lock1.tryLock(){
try {
System.out.println (Thread.currentThread()
. getId()+":My Job done");
return;
} finally {
lock1.unlock();
}
]finally-{
lock2.unlock();
}
}
}
}
}
public static void main(String[] args) throws InterruptedException {
TryLock r1 = new TryLock(1);
TryLock r2= new Trylock(2);Thread tl = new Thread(r1);Thread t2 = new Thread(r2);t1.start();
t2.start();
}
}
- The above code uses a very deadlock prone sequence . That is to say, let t1 get lock1, let t2 get lock2, Then make a reverse request , Give Way t1 apply lock2,t2 apply lock1. In general , This can lead to tl and t2 Wait for each other , And cause a deadlock .
- But use tryLock() After the method , This situation is greatly improved . Because threads don't wait foolishly , It's about trying , therefore , As long as it takes long enough , Threads always get all the resources they need , So as to execute normally ( In this case, the thread gets lock1 and lock2 Two locks , As a condition of its normal execution ). Get at the same time lock1 and lock2 after , The thread prints out information indicating the completion of the task “My Jobdone”.
- Execute the above code , Wait a moment ( Because the thread contains sleep 500
Millisecond code ). In the end, you'll be glad to see the program complete , And produce the following output , Indicates that both threads are executing normally .
3、 ... and 、 Fair lock
- in the majority of cases , Lock applications are unfair . in other words , Threads 1 First, the lock was requested A, Then thread ⒉ I also asked for a lock A. Then when the lock A When available , Is the thread 1 Can you get a lock or a thread 2 You can get the lock ? This is not necessarily , The system just randomly selects one from the waiting queue of the lock . So there's no guarantee of fairness . It's like buying tickets without waiting in line , Everyone is at the ticket window , The conductor was in a hurry , I don't care who comes first , Just ask someone to issue a ticket . And fair lock , Not so , It will be in chronological order , Make sure that the first come first , Later comers, later comers . One of the characteristics of fair lock is : It doesn't produce hunger . As long as you line up , Finally, we can wait for the resources . If we use synchronized Key to lock control , Then the lock is unfair . The reentry lock allows us to set its fairness . Its constructor is as follows :
- When parameters fair by
true when , It means the lock is fair . Fair lock looks beautiful , But to achieve fair locking, the system must maintain an orderly queue , Therefore, the implementation cost of fair lock is relatively high , But the performance is very low , therefore , By default , Locks are unfair . If there is no special need , You don't need to use a fair lock . Fair locks and unfair locks are also very different in thread scheduling performance . The following code highlights the features of fair locks :
Insert picture description here
Above code ﹖ The row specifies that the lock is fair . next , from t1 and t2 Two threads request the lock respectively , And after getting the lock , Perform a console output , Show that you've got the lock . In the case of fair lock , The resulting output is usually as follows :
Because the code produces a lot of output , Here, only the part is intercepted for description . In this output , It is obvious that , The two threads basically acquire locks alternately , It is almost impossible for the same thread to acquire locks several times in succession , This ensures fairness . If you don't use fair locks , Then it's going to be totally different , Here's part of the output when using unfair locks :
You can see , According to the scheduling of the system , A thread tends to acquire a lock that it already holds again , This distribution is efficient , But there's no fairness . Right up there ReentrantLock Several important methods are as follows . - lock(): Gets the lock , If the lock is already occupied , Is waiting for .
- lockInterruptibly(): Gets the lock , But the priority response is interrupted .
- tryLock(): Trying to get a lock , If it works , Then return to true, Failure to return false. The method doesn't wait , Return immediately .
- tryLock(long time, TimeUnit unit): Try to acquire a lock within a given time .unlock(): Release the lock .
In terms of the implementation of reentry locks , It mainly focuses on Java level . In the implementation of reentry locks , There are three main elements .
- First of all , Atomic state . Atomic states use CAS operation ( In the 4 This chapter discusses in detail ) To store the status of the current lock , Determine whether the lock has been held by another thread .
- second , Waiting in line . All threads that do not request locks , Will enter the waiting queue to wait . After a thread releases the lock , The system can wake up a thread from the waiting queue , Keep working .
- Third , Blocking primitive park() and unpark(), Used to suspend and resume threads . Threads without locks will be suspended . of park) and unpark() Detailed introduction , Refer to section 3.1.7 Section thread blocking tool class :LockSupport.
Excerpt from JAVA High concurrency programming , Recommend
边栏推荐
- 2022 safety officer-c certificate examination questions and mock examination
- Pat a-1165 block reversing (25 points)
- Opencascade7.6 compilation
- 附加:信息脱敏;
- QT使用sqllite
- 【带你学c带你飞】day 5 第2章 用C语言编写程序(习题2)
- Open that kind of construction document
- [untitled]
- How to execute an SQL in MySQL
- Learning notes of software testing -- theoretical knowledge of software testing
猜你喜欢
Build a modern data architecture on the cloud with Amazon AppFlow, Amazon lake formation and Amazon redshift
STM32__05—PWM控制直流电机
[question] - why is optical flow not good for static scenes
[liuyubobobo play with leetcode algorithm interview] [00] Course Overview
Vsocde has cli every time it is opened js
MVVM and MVC
[technology development -21]: rapid overview of the application and development of network and communication technology -1- Internet Network Technology
[learn C and fly] 4day Chapter 2 program in C language (exercise 2.5 generate power table and factorial table
How to turn off the LED light of Rog motherboard
Query word weight, search word weight calculation
随机推荐
RTL8189FS如何关闭Debug信息
A quick understanding of analog electricity
[reading notes] programmer training manual - practical learning is the most effective (project driven)
[technology development -21]: rapid overview of the application and development of network and communication technology -1- Internet Network Technology
Set status bar color
Connected block template and variants (4 questions in total)
Feature query of hypergraph iserver rest Service
【读书笔记】程序员修炼手册—实战式学习最有效(项目驱动)
C write TXT file
Iterative unified writing method of binary tree
The basic steps of using information theory to deal with scientific problems are
leetcode2311. Longest binary subsequence less than or equal to K (medium, weekly)
软件开发生命周期 --瀑布模型
leetcode2305. 公平分发饼干(中等,周赛,状压dp)
Use the open source project [banner] to achieve the effect of rotating pictures (with dots)
JPM 2021 most popular paper released (with download)
leetcode2312. Selling wood blocks (difficult, weekly race)
Is bone conduction earphone better than traditional earphones? The sound production principle of bone conduction earphones is popular science
剑指 Offer 31. 栈的压入、弹出序列
STM32F103——两路PWM控制电机