zoukankan      html  css  js  c++  java
  • 用Demo 去理解Java Object 的 wait() 和 notify() 方法

    *JAVA线程同步中wait()和notify()简洁例子 *
    搞懂这两个的用法之前,请你务必搞懂线程同步的道理,否则,下面这一大篇你应该是看不懂的。
    wait()和notify()一系列的方法,是属于对象的,不是属于线程的。它们用在线程同步时,synchronized语句块中。
    我们都知道,在synchronized语句块中,同一个对象,一个线程在执行完这一块代码之前,另一个线程,如果传进来的是同一个object,是不能进入这个语句块的。也就是说,同一个对象是不能同时被两个线程用来进入synchronized中的。这就是线程同步。废话不多说,先用通俗一点的语言来解释一下wait()和notify():

    wait()意思是说,我等会儿再用这把锁,CPU也让给你们,我先休息一会儿!
    notify()意思是说,我用完了,你们谁用?

    也就是说,wait()会让出对象锁,同时,当前线程休眠,等待被唤醒,如果不被唤醒,就一直等在那儿。
    notify()并不会让当前线程休眠,但会唤醒休眠的线程。
    先看第一个例子!

    public class ThreadF {
    
        public static void main(String[] args) {
            final Object object = new Object();
            Thread t1 = new Thread() {
                public void run() {
                    synchronized (object) {
                        System.out.println("T1 start!");
                        try {
                            object.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("T1 end!");
                    }
                }
            };
            Thread t2 = new Thread() {
                public void run() {
                    synchronized (object) {
                        System.out.println("T2 start!");
                        object.notify();
                        System.out.println("T2 end!");
                    }
                }
            };
    
            t1.start();
            t2.start();
    
        }
    
    }

    1:这第一个例子很简单,写了两个线程(分别是两个类,两个run方法)。
    两个run方法之间没有关系,但是,他们都用了同一个object!
    仔细看,T1里面主要写了个wait(),而T2里面主要写了个notify()。
    我们看到执行结果是:
    T1 start!
    T2 start!
    T2 end!
    T1 end!
    流程可以这样解释:
    T1启动,让出锁,让出CPU,T2获得CPU,启动,唤醒使用了object的休眠的线程,T1被唤醒后等待启动,T2继续执行,T2执行完,T1获得CPU后继续执行。
    值得一提的是,再强调一遍:
    wait会让出CPU而notify不会,notify重在于通知使用object的对象“我用完了!”,wait重在通知其它同用一个object的线程“我暂时不用了”并且让出CPUT。
    所以说,看上面的顺序,
    T2 start!
    T2 end!
    是连续的,说明它并没有因调用了notify而暂停!

    那么,如果两个线程都写wait没有线程写notify会有什么现象呢?试一下就知道了。
    结果是,
    T1 start!
    T2 start!
    然后就是一直等待!
    道理很显然,T1先启动,然后wait了,T2获得了锁和CPU,在没有其它线程与它竞争的情况下,T2执行了,然后也wait了。
    在这里,两个线程都在等待,没有其它线程将它们notify,所以结果就是无休止地等下去!
    至少说明了一点,wait后如果没有其它线程将它notify,是绝不可能重新启动的。不可能因为目前没有线程占用CPU,某一个正在等待的线程就自动重启。

    2:下面,我再把它改一下,写四个线程,分别是
    T1 wait()
    T2 notify()
    T3 notify()
    T4 wait()

    public class ThreadF {
    
    	public static void main(String[] args) {
    		final Object object = new Object();
    		Thread t1 = new Thread() {
    			public void run() {
    				synchronized (object) {
    					System.out.println("T1 start!");
    					try {
    						object.wait();
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    					System.out.println("T1 end!");
    				}
    			}
    		};
    		Thread t2 = new Thread() {
    			public void run() {
    				synchronized (object) {
    					System.out.println("T2 start!");
    					object.notify();
    					System.out.println("T2 end!");
    				}
    			}
    		};
    		Thread t3 = new Thread() {
    			public void run() {
    				synchronized (object) {
    					System.out.println("T3 start!");
    					object.notify();
    					System.out.println("T3 end!");
    				}
    			}
    		};
    		Thread t4 = new Thread() {
    			public void run() {
    				synchronized (object) {
    					System.out.println("T4 start!");
    					try {
    						object.wait();
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    					System.out.println("T4 end!");
    				}
    			}
    		};
    		t1.start();
    		t2.start();
    		t3.start();
    		t4.start();
    	}
    
    }
    

      

    首先,大家知道,线程启动的顺序,和代码的先后顺序,理论上是没有关系的!
    比如我这儿写的是按T1-T2-T3-T4的先后顺序先后start(),但实际上谁先启动,是有一定几率的。
    执行上面代码,有两种结果:
    一种是刚好wait两次,notify两次,notify在wait之后执行,刚好执行完。
    另一种是,也是刚好wait两次,notify两次,但是,notify在wait之前执行,于是,至少会有一个线程由于后面没有线程将它notify而无休止地等待下去!
    我摘选了两种情况的输出结果,仅供参考:
    1、可以执行结束的情况:
    T1 start!
    T2 start!
    T2 end!
    T1 end!
    T4 start!
    T3 start!
    T3 end!
    T4 end!
    执行流程是:
    T1启动,wait,T2获得锁和CPU,T2宣布锁用完了其它线程可以用了,然后继续执行,T2执行完,T1被刚才T2唤醒后,等待T2执行完后,抢到了CPU,T1执行,
    T1执行完,T4获得CPU,启动,wait,T3获得了锁和CPU,执行,宣布锁用完了,其它线程可以用了,然后继续执行,T3执行完,已经被唤醒并且等待已久的T4
    得到CPU,执行。
    2、不能执行结束,有线程由于没有其它线程唤醒,一直在等待中:
    T1 start!
    T2 start!
    T2 end!
    T1 end!
    T3 start!
    T3 end!
    T4 start!
    执行流程:
    T1启动,wait,让出CPU和锁,T2得以启动。T2启动,并唤醒一个线程,自己继续执行。被唤醒的线程,也就是T1等待启动机会。
    T2执行完,T1抢到了CPU,执行,并结束。
    这时,只剩下T3和T4,在此时,两个线程的机会均等。
    但是,T3抢到了CPU,于是它执行了,而且唤醒了线程,虽然此时并没有线程休眠。说白了,它浪费了一次notify。T3顺利执行完。
    这时,终于轮到了T4,它启动了,wait了,但是,后面已经没有线程了,它的wait永远不会有线程帮它notify了!
    于是,它就这么等着!

    请仔细看执行流程,看懂,再自己做一下试验。
    仔看看,你会看到,凡是当前线程的run方法里面写了notify,有了start马上就会end,而如果是写的wait,有了start,下一个绝对不是输出这个线程的end。
    所以说,T2和T3由于是写的notify,它们的start和end总是成对出现。而T1和T4由于是写的wait,它们start后,下一个绝不可能是它的end。
    最后再提醒一下,我们的wait和notify是针对同一个object的,而非线程。我们这一篇都在讲对象锁,而不是线程。

    顺便说一下,如果没有线程在wait,调用notify是不会有什么问题的,就像这样:

    public class ThreadG {
        public static void main(String[] args) {
            final Object object = new Object();
            Thread t1 = new Thread() {
                public void run() {
                    synchronized (object) {
                        System.out.println("T1 start!");
                        object.notify();
                        System.out.println("T1 end!");
                    }
                }
            };
            t1.start();
        }
    }

    T1 start!
    T1 end!

    &*******内容获取百度文库*******&通俗易懂,互相学习;
  • 相关阅读:
    《Django By Example》第十二章(终章) 中文 翻译 (个人学习,渣翻)
    《Django By Example》第十一章 中文 翻译 (个人学习,渣翻)
    《Django By Example》第十章 中文 翻译 (个人学习,渣翻)
    《Django By Example》第九章 中文 翻译 (个人学习,渣翻)
    《Django By Example》第八章 中文 翻译 (个人学习,渣翻)
    《Django By Example》第五章 中文 翻译 (个人学习,渣翻)
    我的superui开源后台bootstrap开发框架
    LayoutInflater 总结
    Android屏幕分辨率概念(dp、dip、dpi、sp、px)
    android studio安装问题
  • 原文地址:https://www.cnblogs.com/Ankermaker/p/8670071.html
Copyright © 2011-2022 走看看