一.查看APIthis
sleep是Thread类的方法,致使此线程暂停执行指定时间,给其余线程执行机会,可是依然保持着监控状态,过了指定时间会自动恢复,调用sleep方法不会释放锁对象。spa
当调用sleep方法后,当前线程进入阻塞状态。目的是让出CPU给其余线程运行的机会。可是因为sleep方法不会释放锁对象,因此在一个同步代码块中调用这个方法后,线程虽然休眠了,但其余线程没法访问它的锁对象。这是由于sleep方法拥有CPU的执行权,它能够自动醒来无需唤醒。而当sleep()结束指定休眠时间后,这个线程不必定当即执行,由于此时其余线程可能正在运行。线程
wait方法是Object类里的方法,当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,同时释放了锁对象,等待期间能够调用里面的同步方法,其余线程能够访问,等待时不拥有CPU的执行权,不然其余线程没法获取执行权。当一个线程执行了wait方法后,必须调用notify或者notifyAll方法才能唤醒,并且是随机唤醒,如果被其余线程抢到了CPU执行权,该线程会继续进入等待状态。因为锁对象能够时任意对象,因此wait方法必须定义在Object类中,由于Obeject类是全部类的基类。code
二.是否能够传入参数对象
sleep()方法必须传入参数,参数就是休眠时间,时间到了就会自动醒来。blog
wait()方法能够传入参数也能够不传入参数,传入参数就是在参数结束的时间后开始等待,不穿如参数就是直接等待。进程
三.是否须要捕获异常资源
sleep方法必需要捕获异常,而wait方法不须要捕获异常。sleep方法属于Thread类中方法,表示让一个线程进入睡眠状态,等待必定的时间以后,自动醒来进入到可运行状态,不会立刻进入运行状态,由于线程调度机制恢复线程的运行也须要时间,一个线程对象调用了sleep方法以后,并不会释放他所持有的全部对象锁,因此也就不会影响其余进程对象的运行。但在sleep的过程当中过程当中有可能被其余对象调用它的interrupt(),产生InterruptedException异常,若是你的程序不捕获这个异常,线程就会异常终止,进入TERMINATED状态,若是你的程序捕获了这个异常,那么程序就会继续执行catch语句块(可能还有finally语句块)以及之后的代码。同步
wait属于Object的成员方法,一旦一个对象调用了wait方法,必需要采用notify()和notifyAll()方法唤醒该进程;若是线程拥有某个或某些对象的同步锁,那么在调用了wait()后,这个线程就会释放它持有的全部同步资源,而不限于这个被调用了wait()方法的对象。wait()方法也一样会在wait的过程当中有可能被其余对象调用interrupt()方法而产生。it
四.做用范围
wait、notify和notifyAll方法只能在同步方法或者同步代码块中使用,而sleep方法能够在任何地方使用。可是注意sleep是静态方法,也就是说它只对当前对象有效。经过对象名.sleep()想让该对象线程进入休眠是无效的,它只会让当前线程进入休眠。
五.调用者的区别
首先为何wait、notify和notifyAll方法要和synchronized关键字一块儿使用?
由于wait方法是使一个线程进入等待状态,而且释放其所持有的锁对象,notify方法是通知等待该锁对象的线程从新得到锁对象,然而若是没有得到锁对象,wait方法和notify方法都是没有意义的,所以必须先得到锁对象再对锁对象进行进一步操做因而才要把wait方法和notify方法写到同步方法和同步代码块中了。
由此可知,wait和notify、notifyAll方法是由肯定的对象即锁对象来调用的,锁对象就像一个传话的人,他对某个线程说停下来等待,而后对另外一个线程说你能够执行了(实质上是被捕获了),这一过程是线程通讯。sleep方法是让某个线程暂停运行一段时间,其控制范围是由当前线程决定,运行的主动权是由当前线程来控制(拥有CPU的执行权)。
其实二者的区别都是让线程暂停运行一段时间,但本质的区别一个是线程的运行状态控制,一个是线程间的通讯。
六.wait方法(线程通讯)的一些注意事项
例如如下代码:
当线程print1得到了锁对象(this)后进行判断,若是不知足条件(flag == 1)没法继续执行下面的代码,因而进入wait状态。在另外一个线程print3中,因为改变了flag,使得线程print1的判断条件知足了,线程print1就会被唤醒。
class Printer { private int flag = 1; public void print1() throws Exception { synchronized(this) { while(flag != 1) { this.wait(); } System.out.print("1"); System.out.print("2"); System.out.print("3"); System.out.print("4"); System.out.println(); flag = 2; this.notifyAll(); } } public void print2() throws Exception { synchronized(this) { while(flag != 2) { this.wait(); } System.out.print("5"); System.out.print("6"); System.out.print("7"); System.out.print("8"); System.out.println(); flag = 3; this.notifyAll(); } } public void print3() throws Exception { synchronized(this) { while(flag != 3) { this.wait(); } System.out.print("A"); System.out.print("B"); System.out.print("C"); System.out.print("D"); System.out.println(); flag = 1; this.notifyAll(); } } }
注意事项:
1.调用wait方法和notify、notifyAll方法前必须得到对象锁,也就是必须写在synchronized(锁对象){......}代码块中。
2.当线程print1调用了wait方法后就释放了对象锁,不然其余线程没法得到对象锁,也就没法唤醒线程print1。
3.当this.wait()方法返回后,线程必须再次得到对象锁后才能继续执行。
4.若是另外两个线程都在wait,则正在执行的线程调用notify方法只能唤醒一个正在wait的线程(公平竞争,由JVM决定)。
5.当使用notifyAll方法后,全部wait状态的线程都会被唤醒,可是只有一个线程能得到锁对象,必须执行完while(condition){this.wait();}后才能得到对象锁。其他的须要等待该得到对象锁的线程执行完释放对象锁后才能继续执行。
6.当某个线程调用notifyAll方法后,虽然其余线程被唤醒了,可是该线程依然持有着对象锁,必须等该同步代码块执行完(右大括号结束)后才算正式释放了锁对象,另外两个线程才有机会执行。