16、可重入锁和LockSurport

2021-03-03  本文已影响0人  i小雨

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

使用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个,累加无效。

上一篇 下一篇

猜你喜欢

热点阅读