zoukankan      html  css  js  c++  java
  • Java多线程5-线程等待与唤醒

    1、wait(),notify(),notifyAll()等方法介绍

    在object.java中,定义了wait(),notify(),notifyAll()等接口。wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。而notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程。

    object类中关于等待/唤醒的API详细信息如下:

    notify():唤醒在此对象监视器上等待的单个线程。

    notifyAll():唤醒在此对象监视器上等待的所有线程。

    wait():让当前线程处于“等待/阻塞”状态,直到其他线程调用此对象的notify()或notifyAll()方法,当前线程被唤醒(进入“就绪态”)。

    wait(long timeout):让当前线程处于“等待/阻塞”状态,直到其他线程调用此对象的notify()方法或notifyAll()方法,或者其他某个线程终端当前线程,或者已超过某个实际时间量,当前线程被唤醒(进入就绪态)。

    2、wait()和notify()实例

    下面通过示例演示“wait()和notify()使用的情形”

    class ThreadA extends Thread
    {
        public ThreadA(String name)
        {
            super(name);
        }
    
        public void run()
        {
            synchronized(this)
            {
                System.out.println(Thread.currentThread().getName()+" call notify()");
                notify();
            }
        }
    }
    public class WaitTest
    {
        public static void main(String[] args)
        {
            ThreadA t1 = new ThreadA("t1");
    
            synchronized (t1)
            {
                try
                {
                    System.out.println(Thread.currentThread().getName()+" start t1");
    
                    t1.start();
    
                    System.out.println(Thread.currentThread().getName()+" wait()");
                    t1.wait();
    
                    System.out.println(Thread.currentThread().getName()+" continue");
                }
                catch (InterruptedException ie)
                {
                    ie.printStackTrace();
                }
            }
        }
    }

    运行结果为:

    main start t1
    main wait()
    t1 call notify()
    main continue

    结果说明:

    1、主线程通过new ThreadA("t1")新建线程t1。随后通过synchronized(t1)获取“t1”对象的同步锁,然后调用t1.start()启动线程t1

    2、主线程执行t1.wait()释放t1对象的锁,并且进入等待(阻塞)状态。等待t1对象上的线程通过notify()或者notifyAll()将其唤醒

    3、线程t1运行之后,通过synchronized(this)获取“当前对象”的锁,接着调用notify()唤醒当前对象上的等待线程,也就是唤醒主线程

    4、线程t1运行完毕之后,释放“当前对象的锁”。紧接着,主线程获取t1对象的锁,然后接着运行

    3、wait(long timeout)和notify()

    wait(long timeout)会让当前线程处于“等待/阻塞”状态,“直到其他线程调用此对象的notify()方法或者notifyAll()方法,或者超过指定的时间量”,当前线程被唤醒。

    下面是示例:

    class ThreadA extends Thread
    {
        public ThreadA(String name)
        {
            super(name);
        }
    
        public void run()
        {
            System.out.println(Thread.currentThread().getName()+" run ");
    
            while(true)
                ;
        }
    }
    public class WaitTimeoutTest
    {
        public static void main(String[] args)
        {
            ThreadA t1 = new ThreadA("t1");
    
            synchronized (t1)
            {
                try
                {
                    System.out.println(Thread.currentThread().getName()+" start t1");
    
                    t1.start();
    
                    System.out.println(Thread.currentThread().getName()+" wait()");
                    t1.wait(3000);
    
                    System.out.println(Thread.currentThread().getName()+" continue");
                }
                catch (InterruptedException ie)
                {
                    ie.printStackTrace();
                }
            }
        }
    }

    运行结果:

    main start t1
    main wait()
    t1 run 
    main continue //上一句三秒后输出这一句

    结果说明:

    1、主线程main通过执行t1.start()启动线程t1

    2、主线程main执行t1.wait(3000),此时,主线程进入阻塞状态。需要用于t1对象锁的线程通过notify()或者notifyAll()将其唤醒或者超时3000ms,主线程main才能进入就绪状态

    3、线程t1运行之后,陷入死循环

    4、超过3000ms之后,主线程进入就绪态,然后进入运行状态

    4、wait()和notifyAll()

    现在演示notifyAll()的用法,它的作用是唤醒在此对象监视器上的所有线程

    public class WaitTimeoutTest
    {
        private static Object obj = new Object();
        public static void main(String[] args)
        {
            ThreadA t1 = new ThreadA("t1");
            ThreadA t2 = new ThreadA("t2");
            ThreadA t3 = new ThreadA("t3");
    
            t1.start();
            t2.start();
            t3.start();
    
            try
            {
                System.out.println(Thread.currentThread().getName()+" sleep(3000)");
                Thread.sleep(3000);
            }
            catch (InterruptedException ie)
            {
                ie.printStackTrace();
            }
    
            synchronized (obj)
            {
                System.out.println(Thread.currentThread().getName()+" notifyAll");
    
                obj.notifyAll();
            }
    
        }
    
        static class ThreadA extends Thread
        {
            public ThreadA(String name)
            {
                super(name);
            }
    
            public void run()
            {
                synchronized (obj)
                {
                    try
                    {
                        System.out.println(Thread.currentThread().getName()+" wait");
                        obj.wait();
                        System.out.println(Thread.currentThread().getName()+" continue");
                    }
                    catch (InterruptedException ie)
                    {
                        ie.printStackTrace();
                    }
                }
            }
        }
    }

    运行结果:

    main sleep(3000)
    t1 wait
    t2 wait
    t3 wait
    main notifyAll
    t3 continue
    t2 continue
    t1 continue

    结果说明:

    1、主线程中新建并启动了三个线程t1,t2,t3

    2、主线程通过sleep(3000)休眠3秒,在主线程休眠三秒的过程中,我们假设t1,t2,t3这三个线程都运行了。以t1为例,当他运行的时候,会执行obj.wait()等待其他线程通过notify()或者notifyAll()来唤醒它;相同的,t2和t3也会等待

    3、主线程休眠3s以后,接着运行。执行obj.notifyAll()唤醒obj上的等待线程,即唤醒t1,t2,t3。紧接着,主线程的synchronized(obj)运行完毕之后,主线程释放“obj”锁,这样t1,t2,t3就可以接着运行了

    5、为什么notify(),wait()等函数定义在object中,而不是Thread中

    object中的wait(),notify()等函数,和synchronized一样,会对“对象的同步锁”进行操作。

    wait()使当前进程等待,因为线程进入等待状态,所以线程应该释放它所持有的“同步锁”,否则其他线程获取不到该“同步锁”而无法运行

    线程调用wait()之后,会释放它所持有的“同步锁”;而且,等待线程可以被notify()和notifyAll()唤醒。而notify()就是根据对象的同步锁唤醒线程的

    负责唤醒等待线程的那个线程,他只有在获取“该对象的同步锁”(这里的同步锁必须和等待线程的同步锁是同一个,并且调用notify()或者notifyAll()方法之后,才能唤醒等待线程。虽然,等待线程被唤醒;但是,他不能立刻执行,因为唤醒线程还持有“该对象的同步锁”。必须等到唤醒线程释放了“该对象的同步锁”之后,等待线程才能获取到“对象的同步锁”,从而开始运行

    总之,notify(),wait()依赖于“同步锁”,而“同步锁”是对象所持有的,并且每个对象有且只有一个。所以notify()和wait()定义在object类,而不是Thread类中。

  • 相关阅读:
    C++中整型变量的存储大小和范围
    A1038 Recover the Smallest Number (30 分)
    A1067 Sort with Swap(0, i) (25 分)
    A1037 Magic Coupon (25 分)
    A1033 To Fill or Not to Fill (25 分)
    A1070 Mooncake (25 分)
    js 获取控件
    C#代码对SQL数据库添加表或者视图
    JS 动态操作表格
    jQuery取得下拉框选择的文本与值
  • 原文地址:https://www.cnblogs.com/qumasha/p/12824916.html
Copyright © 2011-2022 走看看