美文网首页
16、可重入锁和LockSurport

16、可重入锁和LockSurport

作者: i小雨 | 来源:发表于2021-03-03 11:35 被阅读0次
    • 定义:LockSurport是用来创建锁和其他同步类的基本线程阻塞原语
      LockSurport类使用了一种名为permit(许可)的概念来做阻塞和唤醒线程的功能,每个线程都有一个许可(permit)。permit只有0和1两个值,默认是0.
      可以把两个值0和1看成信号量(semaphore),但与semaphore不同的是,许可的累加上限是1.

    三种让线程等待和唤醒的方法:

    • 1、使用Object中的wait()方法让线程等待,使用Object中的notify()方法唤醒线程。
    • 2、使用JUC包中Condition的await()方法让线程等待,使用signal()方法唤醒线程。
    • 3、LockSurport类可以阻塞当前线程(park())以及唤醒指定被阻塞的线程(unpark())

    使用wait和notify:

    public class TestWaitAndNotify {
        static Object objectLock = new Object();
        
        public static void main(String[] args) {
            
            new Thread(()->{
                try {
                    TimeUnit.SECONDS.sleep(3); //暂停3秒为了让notify先执行,会导致wait的线程不能被唤醒
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
                synchronized (objectLock) {
                    System.out.println(Thread.currentThread().getName()+"---come in");
                    try {
                        objectLock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"---被唤醒");
                }
            },"A").start();
            
            new Thread(()->{
                synchronized (objectLock) {
                    objectLock.notify();;
                    System.out.println(Thread.currentThread().getName()+"---通知");
                }
            },"B").start(); 
        }
    }
    *************结果***************
    B---通知
    A---come in
    **********************分析:******************
    1、wait(),notify(),notifyAll() 必须结合synchronized使用
    2、先wait,后notify,否则wait的线程无法被唤醒。
    

    使用await和signal

    public class TestAwaitAndSignal {
        
        static Lock lock = new ReentrantLock();
        static Condition condition = lock.newCondition();
        
        public static void main(String[] args) {
            
            new Thread(()->{
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName()+"---come in");
                    try {
                        condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"---被唤醒");
                } finally {
                    lock.unlock();
                }
                
            },"A").start();
            
            new Thread(()->{
                lock.lock();
                try {
                    condition.signal();
                    System.out.println(Thread.currentThread().getName()+"----通知");
                } finally {
                    lock.unlock();
                }
            },"B").start();
                    
        }
    
    }
    *************结果***************
    B---通知
    A---come in
    **********************分析:******************
    1、await(),signal(),signalAll() 必须结合lock使用
    2、先await,后signal,否则等待的线程无法被唤醒。
    

    可以发现:synchronized和lock的等待唤醒必须先等待后唤醒,程序才能正常执行。

    LockSurport

    通过park()和unpark()实现阻塞和唤醒线程的操作。

    public class TestLockSurport {
        
        public static void main(String[] args) {
            
            Thread a = new Thread(()->{
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
                System.out.println(Thread.currentThread().getName()+"---come in");
                
                LockSupport.park();//被阻塞,等待通发放许可证permit
                
                System.out.println(Thread.currentThread().getName()+"---被唤醒");
            },"A");
            a.start();
            
            
            Thread b = new Thread(()->{
                LockSupport.unpark(a);
                System.out.println(Thread.currentThread().getName()+"---通知");
            },"B");
            b.start();      
        }
    }
    ******************结果:*******************
    B---通知
    A---come in
    A---被唤醒
    **********************分析:******************
    1、可以看到先通知后等待,也会唤醒等待的线程。
    
    图片.png

    当调用park方法时

    • 如果有凭证,则会直接消耗掉这个凭证然后正常退出;
    • 如果无凭证,就必须阻塞等待凭证可用。

    unpark则相反
    它会增加一个凭证,但凭证最多只能有1个,累加无效。

    相关文章

      网友评论

          本文标题:16、可重入锁和LockSurport

          本文链接:https://www.haomeiwen.com/subject/letqqltx.html