可重入锁和LockSupport相关
作者:互联网
代码块方式
public class ReEnterLockDemo { static Object objectLockA = new Object(); public static void m1() { new Thread(() -> { synchronized (objectLockA) { System.out.println(Thread.currentThread().getName() + "\t" + "---外层调用"); synchronized (objectLockA) { System.out.println(Thread.currentThread().getName() + "\t" + "---外层调用"); synchronized (objectLockA) { System.out.println(Thread.currentThread().getName() + "\t" + "---外层调用"); } } } },"t1").start(); } public static void main(String[ ]args ) { m1(); } }
代码方法:
public class ReEnterLockDemo1 { public synchronized void m1(){ System.out.println("----外层"); m2(); } public synchronized void m2(){ System.out.println("----中层"); m3(); } public synchronized void m3(){ System.out.println("----内层"); } public static void main(String args[]) { ReEnterLockDemo1 reEnterLockDemo1 = new ReEnterLockDemo1(); reEnterLockDemo1.m1(); } }
wait 和notify
public class LockSupportDemo { static Object objectLock = new Object(); public static void main(String[] args) { new Thread( () -> { synchronized (objectLock) { System.out.println(Thread.currentThread().getName() +"\t" +"----come in"); try { objectLock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() +"\t" +"---- 被唤醒"); } },"A").start(); new Thread( () -> { synchronized (objectLock) { System.out.println(Thread.currentThread().getName() +"\t" +"----被通知"); try { objectLock.notify(); } catch (Exception e) { e.printStackTrace(); } } },"B").start(); } }
结论:1.wait方法和notify方法,两个都需要同步代码块,否则会抛异常
2. 将notify放在wait方法前面,程序无法执行,无法唤醒
lock 实例
public class LockSupportDemo1 { static Lock lock = new ReentrantLock(); static Condition condition = lock.newCondition(); public static void main(String[] args) { new Thread( () -> { lock.lock(); System.out.println(Thread.currentThread().getName() +"\t" +"----come in"); try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() +"\t" +"---- 被唤醒"); lock.unlock(); },"A").start(); new Thread( () -> { lock.lock(); try { condition.signal(); System.out.println(Thread.currentThread().getName() +"\t" +"---- 通知"); } catch (Exception e) { e.printStackTrace(); } lock.unlock(); },"B").start(); } }
LockSupport的支持用法
public class LockSupportDemo2 { public static void main(String[] args) { Thread a = new Thread( () -> { System.out.println(Thread.currentThread().getName() +"\t" +"----come in"); LockSupport.park(); System.out.println(Thread.currentThread().getName() +"\t" +"---- 被唤醒"); },"A"); a.start(); Thread b = new Thread( () -> { LockSupport.unpark(a); System.out.println(Thread.currentThread().getName() +"\t" +"----通知了"); },"B"); b.start(); } }
结论:
LockSupport调用的Unsafe中的native代码
LockSupport提供park() 和unpark()方法实现阻塞线程和解除线程阻塞的过程。
LockSupport和每个使用它的线程独有一个许可(permit)关联,permit相当于1,0的开关,默认是0。
调用一次unpark就加1变成1,调用一次park会消费permit,也就是将1变成0,同时park立即返回。
如再次调用park会变成阻塞(因为permit为零了会阻塞在这里,一直到permit变成1),这时调用unpark
会把permit置为1.
每个线程都有一个相关的permit,permit最多只有1个,重复调用unpark也不会阻塞凭证
形象的理解
线程阻塞需要消耗凭证(permit),这个凭证最多只有1个
当调用park方法时
如果有凭证,则会直接消耗掉这个凭证然后正常退出,
如果无凭证就必须阻塞等待凭证可用。
而unpark则相反,它会增加一个凭证,但凭证最多只能有1个,累加无效。
面试题:
1.为什么可以唤醒线程后阻塞线程?
因为unpark获得了一个凭证,之后再调用park方法,就可以名正言顺的凭证消费,故不会阻塞。
2. 为什么唤醒两次后阻塞两次,但最终结果还会阻塞线程?
因为凭证的数量最多为1,连续调用两次unpark和调用一次unpark效果一样,只会增加一个凭证,
而调用两次park却需要消费两个凭证,证不够,不能放行。
--摘自 周阳老师
标签:重入,Thread,getName,System,LockSupport,println,相关,public,out 来源: https://www.cnblogs.com/liuyi13535496566/p/14433448.html