Author: Pheasant
Locks, as a tool for concurrently sharing data and ensuring consistency, are implemented in a variety of ways on JAVA platforms (such as synchronized and ReentrantLock).These locks, which have been written to provide convenience for our development, are rarely mentioned in terms of their specific nature and type.This series of articles will analyze common lock names and features under JAVA to help you answer questions.
4. Re-entrainable locks:
Instead of referring to ReentrantLock under JAVA, this article deals with a generalized re-entrantLock.
Re-entrant locks, also known as recursive locks, refer to internal recursive functions that still have code to acquire locks after the same thread's outer functions have acquired them, but are unaffected.
ReentrantLock and synchronized are re-lockable in a JAVA environment
Here is an example of use
public class Test implements Runnable{
public synchronized void get(){
System.out.println(Thread.currentThread().getId());
set();
}
public synchronized void set(){
System.out.println(Thread.currentThread().getId());
}
@Override
public void run() {
get();
}
public static void main(String[] args) {
Test ss=new Test();
new Thread(ss).start();
new Thread(ss).start();
new Thread(ss).start();
}
}
public class Test implements Runnable {
ReentrantLock lock = new ReentrantLock();
public void get() {
lock.lock();
System.out.println(Thread.currentThread().getId());
set();
lock.unlock();
}
public void set() {
lock.lock();
System.out.println(Thread.currentThread().getId());
lock.unlock();
}
@Override
public void run() {
get();
}
public static void main(String[] args) {
Test ss = new Test();
new Thread(ss).start();
new Thread(ss).start();
new Thread(ss).start();
}
}
The final result of both examples is correct, that is, the same thread id is output twice in a row.
The results are as follows:
Threadid: 8
Threadid: 8
Threadid: 10
Threadid: 10
Threadid: 9
Threadid: 9
The greatest effect of reentrant locks is to avoid deadlocks
Let's take the spin lock as an example.
public class SpinLock {
private AtomicReference<Thread> owner =new AtomicReference<>();
public void lock(){
Thread current = Thread.currentThread();
while(!owner.compareAndSet(null, current)){
}
}
public void unlock (){
Thread current = Thread.currentThread();
owner.compareAndSet(current, null);
}
}
For spin locks,
1. If lock() is called twice by the same thread, it will cause the second lock call to spin and result in a deadlock
Indicates that the lock is not reentrant.(Within the lock function, you should verify that the thread is one that has already acquired a lock)
2. If the problem has been solved, the lock will be released when unlock () is called for the first time.The lock should not actually be released.
(counting times)
After modification, the following:
public class SpinLock1 {
private AtomicReference<Thread> owner =new AtomicReference<>();
private int count =0;
public void lock(){
Thread current = Thread.currentThread();
if(current==owner.get()) {
count++;
return ;
}
while(!owner.compareAndSet(null, current)){
}
}
public void unlock (){
Thread current = Thread.currentThread();
if(current==owner.get()){
if(count!=0){
count--;
}else{
owner.compareAndSet(current, null);
}
}
}
}
The spin lock is re-entrant.