可重入锁/不可重入锁
原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11395621.html
可重入锁
可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁(前提是同一个对象或者类)
Note:
ReentrantLock和synchronized都是可重入锁
1 public class TestLock { 2 public synchronized void test1() throws InterruptedException { 3 Thread.sleep(1000); 4 System.out.println("test1 invoked..."); 5 test2(); 6 } 7 8 public synchronized void test2() throws InterruptedException { 9 Thread.sleep(1000); 10 System.out.println("test2 invoked..."); 11 } 12 13 public static void main(String[] args) throws InterruptedException { 14 TestLock testLock = new TestLock(); 15 testLock.test1(); 16 } 17 }
上面的代码就是一个可重入锁的一个特点,如果不是可重入锁的话,test2可能不会被当前线程执行,可能造成死锁。
不可重入锁
不可重入锁,与可重入锁相反,不可递归调用,递归调用就会发生死锁。
使用自旋锁来模拟一个不可重入锁
1 import java.util.concurrent.atomic.AtomicReference; 2 3 public class UnreentrantLockTest { 4 private static UnreentrantLock lock = new UnreentrantLock(); 5 6 public static void main(String[] args) { 7 lock.lock(); 8 9 test(); 10 11 lock.unlock(); 12 } 13 14 private static void test() { 15 lock.lock(); 16 17 System.out.println("test invoked..."); 18 19 lock.unlock(); 20 } 21 22 private static class UnreentrantLock { 23 private AtomicReference<Thread> owner = new AtomicReference<>(); 24 25 public void lock() { 26 Thread currentThread = Thread.currentThread(); 27 28 for (; ; ) { 29 System.out.println(owner); 30 if (owner.compareAndSet(null, currentThread)) { 31 System.out.println(currentThread + " locked..."); 32 return; 33 } 34 } 35 } 36 37 public void unlock() { 38 Thread currentThread = Thread.currentThread(); 39 40 owner.compareAndSet(currentThread, null); 41 42 System.out.println(currentThread + " unlock..."); 43 } 44 } 45 }
Note:
使用原子引用来存放线程,同一个线程两次调用lock()方法,如果不执行unlock()释放锁的话,第二次调用自旋的时候就会产生死锁,这个锁是不可重入的
修改上述代码,将它改造成可重入锁,在执行每次操作之前,判断当前锁持有者是否是当前对象,采用state计数
1 import java.util.concurrent.atomic.AtomicReference; 2 3 public class ReentrantLockTest { 4 private static ReentrantLock lock = new ReentrantLock(); 5 6 public static void main(String[] args) { 7 lock.lock(); 8 9 test(); 10 11 lock.unlock(); 12 } 13 14 private static void test() { 15 lock.lock(); 16 17 System.out.println("test invoked..."); 18 19 test1(); 20 21 lock.unlock(); 22 } 23 24 private static void test1() { 25 lock.lock(); 26 27 System.out.println("test2 invoked..."); 28 29 lock.unlock(); 30 } 31 32 private static class ReentrantLock { 33 private AtomicReference<Thread> owner = new AtomicReference<>(); 34 private int state = 0; 35 36 public void lock() { 37 Thread currentThread = Thread.currentThread(); 38 39 if (currentThread == owner.get()) { 40 state++; 41 return; 42 } 43 44 for (; ; ) { 45 System.out.println(owner); 46 if (!owner.compareAndSet(null, currentThread)) { 47 return; 48 } 49 } 50 } 51 52 public void unlock() { 53 Thread currentThread = Thread.currentThread(); 54 55 if (currentThread == owner.get()) { 56 if (state != 0) { 57 state--; 58 } else { 59 owner.compareAndSet(currentThread, null); 60 } 61 } 62 } 63 } 64 }
强者自救 圣者渡人