• 用实例揭示notify()和notifyAll()的本质区别


    用实例揭示notify()和notifyAll()的本质区别 收藏

     

    notify()和notifyAll()都是Object对象用于通知处在等待该对象的线程的方法。两者的最大区别在于:

    notifyAll使所有原来在该对象上等待被notify的线程统统退出wait的状态,变成等待该对象上的锁,一旦该对象被解锁,他们就会去竞争。
    notify则文明得多他只是选择一个wait状态线程进行通知,并使它获得该对象上的锁,但不惊动其他同样在等待被该对象notify的线程们,当第一个线程运行完毕以后释放对象上的锁此时如果该对象没有再次使用notify语句,则即便该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的通知,继续处在wait状态,直到这个对象发出一个notify或notifyAll,它们等待的是被notify或notifyAll,而不是锁。

    下面是一个很好的例子:

    import java.util.*;

    class Widget...{}
    class WidgetMaker extends Thread...{
        List<Widget> finishedWidgets=new ArrayList<Widget>();
        public void run()...{
            try...{
                while(true)...{
                    Thread.sleep(5000);//act busy
                    Widget w=new Widget();
                    //也就是说需要5秒钟才能新产生一个Widget,这决定了一定要用notify而不是notifyAll
                    //因为上面两行代码不是同步的,如果用notifyAll则所有线程都企图冲出wait状态
                    //第一个线程得到了锁,并取走了Widget(这个过程的时间小于5秒,新的Widget还没有生成)
                    //并且解开了锁,然后第二个线程获得锁(因为用了notifyAll其他线程不再等待notify语句
                    //,而是等待finishedWidgets上的锁,一旦锁放开了,他们就会竞争运行),运行
                    //finishedWidgets.remove(0),但是由于finishedWidgets现在还是空的,
                    //于是产生异常
                    //***********这就是为什么下面的那一句不能用notifyAll而是要用notify
                                    
                    synchronized(finishedWidgets)...{
                        finishedWidgets.add(w);
                        finishedWidgets.notify(); //这里只能是notify而不能是notifyAll
                    }
                }
            }
            catch(InterruptedException e)...{}
        }
        
        public Widget waitForWidget()...{
            synchronized(finishedWidgets)...{
                if(finishedWidgets.size()==0)...{
                    try...{
                        finishedWidgets.wait();
                    }
                    catch(InterruptedException e)
                    ...{}
                }
                return finishedWidgets.remove(0);
            }
        }
    }
    public class WidgetUser extends Thread...{
        private WidgetMaker maker;
        public WidgetUser(String name,WidgetMaker maker)...{
            super(name);
            this.maker=maker;
        }
        public void run()...{
            Widget w=maker.waitForWidget();
            System.out.println(getName()+"got a widget");
        }
       

        public static void main(String[] args) ...{
            WidgetMaker maker=new WidgetMaker();
            maker.start();
            new WidgetUser("Lenny",maker).start();
            new WidgetUser("Moe",maker).start();
            new WidgetUser("Curly",maker).start();

        }

    }

    本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/SuperMiner/archive/2007/04/22/1574615.aspx

  • 相关阅读:
    SQL Server 2008R2 附件数据库问题记录
    关于.NET C#调用Sqlite的总结二
    关于.NET C#调用Sqlite的总结一
    MS Server中varchar与nvarchar的区别
    Intellij IDEA中使用Debug调试
    使用idea关联mysql时报错Server returns invalid timezone. Go to 'Advanced' tab and set 'serverTimezon'
    学Redis这篇就够了
    java的动态代理机制详解
    mybatis-sql执行流程源码分析
    mybatis
  • 原文地址:https://www.cnblogs.com/w-wfy/p/5893270.html
Copyright © 2020-2023  润新知