让线程等待唤醒的3种方法及各自存在的问题

第一种:使用Object类中的wait()notify()方法实现线程等待和唤醒

正常案例:

public static void main(String[] args) {
        Object object = new Object();

        new Thread(() ->{
            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + "\t ---- come in");
                try {
                    object.wait();
                } catch (InterruptedException e) {
                   e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t ---- 被唤醒");
            }
        }, "A").start();

        //暂停几秒
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() ->{
            synchronized (object) {
                object.notify();
                System.out.println(Thread.currentThread().getName() + "\t ---- 发送通知");
            }
        }, "B").start();
    }

异常案例一

    public static void main(String[] args) {
        Object object = new Object();

        new Thread(() ->{
//            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + "\t ---- come in");
                try {
                    object.wait();
                } catch (InterruptedException e) {
                   e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t ---- 被唤醒");
//            }
        }, "A").start();

        //暂停几秒
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() ->{
//            synchronized (object) {
                object.notify();
                System.out.println(Thread.currentThread().getName() + "\t ---- 发送通知");
//            }
        }, "B").start();
    }

结论:要使用必须包在synchronized 锁之间,必须先持有锁

异常案例二

    public static void main(String[] args) {
        Object object = new Object();

        new Thread(() ->{
            //暂停几秒
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + "\t ---- come in");
                try {
                    object.wait();
                } catch (InterruptedException e) {
                   e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t ---- 被唤醒");
            }
        }, "A").start();



        new Thread(() ->{
            synchronized (object) {
                object.notify();
                System.out.println(Thread.currentThread().getName() + "\t ---- 发送通知");
            }
        }, "B").start();
    }

结论二:将notify放在wait方法前面程序无法执行,无法唤醒

综上所述:wait和notify方法必须要在同步块或者方法里面,且成对出现,必须先wait后notify

第二种:Condition接口中的await后signal方法实现线程的等待和唤醒

正常案例

 public static void main(String[] args) {
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();

        new Thread(() -> {
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "\t ---- come in");
                condition.await();
                System.out.println(Thread.currentThread().getName() + "\t ---- 被唤醒");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally{
                lock.unlock();
            }
        }, "A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            lock.lock();
            try {
                condition.signal();
                System.out.println(Thread.currentThread().getName() + "\t ---- 发送通知");
            } finally {
                lock.unlock();
            }
        }, "B").start();
    }

异常案例

public static void main(String[] args) {
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();

        new Thread(() -> {
//            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "\t ---- come in");
                condition.await();
                System.out.println(Thread.currentThread().getName() + "\t ---- 被唤醒");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally{
//                lock.unlock();
            }
        }, "A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
//            lock.lock();
            try {
                condition.signal();
                System.out.println(Thread.currentThread().getName() + "\t ---- 发送通知");
            } finally {
//                lock.unlock();
            }
        }, "B").start();
    }

结论:必须使用lock()和unlock()

    public static void main(String[] args) {
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();

        new Thread(() -> {

            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "\t ---- come in");
                condition.await();
                System.out.println(Thread.currentThread().getName() + "\t ---- 被唤醒");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally{
                lock.unlock();
            }
        }, "A").start();



        new Thread(()->{
            lock.lock();
            try {
                condition.signal();
                System.out.println(Thread.currentThread().getName() + "\t ---- 发送通知");
            } finally {
                lock.unlock();
            }
        }, "B").start();
    }

线程先要获得并持有锁,必须在锁块(synchronized或lock)中,必须要先等待后唤醒,线程才能够被唤醒

第三种:LockSupport类中的park等待和unpark唤醒
    public static void main(String[] args) {
        Thread thread1 = new Thread(() ->{
            System.out.println(Thread.currentThread().getName() + "\t  ---- come in");
            LockSupport.park();
            System.out.println(Thread.currentThread().getName() + "\t  ---- 被唤醒");
        }, "A");
        thread1.start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            LockSupport.unpark(thread1);
            System.out.println(Thread.currentThread().getName() + "\t  ---- 发送通知");
        }, "B").start();
    }

结论:无锁要求

public static void main(String[] args) {
        Thread thread1 = new Thread(() ->{
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "\t  ---- come in");
            LockSupport.park();
            System.out.println(Thread.currentThread().getName() + "\t  ---- 被唤醒");
        }, "A");
        thread1.start();



        new Thread(() -> {
            LockSupport.unpark(thread1);
            System.out.println(Thread.currentThread().getName() + "\t  ---- 发送通知");
        }, "B").start();
    }

可以先唤醒,再等待

异常案例

public static void main(String[] args) {
        Thread thread1 = new Thread(() ->{
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "\t  ---- come in");
            LockSupport.park();
            LockSupport.park();
            System.out.println(Thread.currentThread().getName() + "\t  ---- 被唤醒");
        }, "A");
        thread1.start();

        new Thread(() -> {
            LockSupport.unpark(thread1);
            LockSupport.unpark(thread1);
            System.out.println(Thread.currentThread().getName() + "\t  ---- 发送通知");
        }, "B").start();
    }

结论: 许可的累加上限是1。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值