JUC-三种等待唤醒方式

一、synchronized的wait和notify

wait方法会释放对象锁资源后进入等待队列,等待被唤醒
notify会唤醒等待队列中的单个线程

	static Object objectLock=new Object();'
	new Thread(()->{
            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){
                System.out.println(Thread.currentThread().getName()+"唤醒");
                 objectLock.notify();
            }
        },"B").start();

特点:
需要搭配synchronized使用,否则会报异常
需要先等待后唤醒,否则会一直等待

二、Lock的await和signal

await会释放掉锁资源,然后当前线程进入等待队列
signal就是会唤醒等待队列中的单个线程

	static Lock lock=new ReentrantLock();
    static Condition condition=lock.newCondition();
		new Thread(()->{
            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 {
                System.out.println(Thread.currentThread().getName() + "唤醒");
                condition.signal();
            } finally {
                lock.unlock();
            }
        },"B").start();

特点:
需要搭配Lock使用,否则会报异常
同样需要先等待后唤醒

三、LookSupport

原理:每个线程都有一个许可证
LookSupport有两个方法

  • park:等待/.阻塞,当前线程的许可证-1(消费当前线程许可证),如果许可证为0就阻塞当前线程,只有调用unpark生产许可证供park消费或者线程中断的时候,才会从park返回
  • unpark:唤醒,为指定线程生产一个许可证,许可证+1

因为许可证的上限是1,所以多次unpark无效
许可证有两个信号量:1和0

     Thread ta=new Thread(()->{
//            try {
//                TimeUnit.SECONDS.sleep(1);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            System.out.println(Thread.currentThread().getName()+" come in");
            LockSupport.park();//消费许可证,如果没有就阻塞
            System.out.println(Thread.currentThread().getName()+" 被唤醒");
        },"A");

        ta.start();

        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"唤醒A");
           LockSupport.unpark(ta);//对当前线程的许可证+1,上限为1
        },"B").start();

面试题

为什么LockSupport可以先唤醒后等待?

因为唤醒操作unpark生产了许可证
等待操作park可以直接消费掉该许可证,不用阻塞

为什么等待两次唤醒两次,最终线程还是会阻塞?

	 Thread ta=new Thread(()->{
            System.out.println(Thread.currentThread().getName()+" come in");
            LockSupport.park();//消费许可证,如果没有就阻塞
            LockSupport.park();
            System.out.println(Thread.currentThread().getName()+" 被唤醒");
        },"A");

        ta.start();

        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"唤醒A");
            LockSupport.unpark(ta);//对当前线程的许可证+1,上限为1
            LockSupport.unpark(ta);
        },"B").start();

A线程第一次park,没有许可证阻塞,没有继续执行
线程B连续两次unpark,但是许可证上限为1,所以当前许可证为1
A线程检测到许可证,park消费一个,往下执行,park没有许可证就阻塞了,但是没有线程生产许可证了

特点

不需要在意线程的等待唤醒顺序
不需要维护同步对象和获得锁,实现了线程的解耦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值