sleep(),wait(),yield(),notify()
sleep(),wait(),yield() 的区别
sleep方法和yield方法是Thread类的方法,wait方法是Object的方法。
sleep 方法使当前运行中的线程睡眼一段时间,进入不可运行状态,这段时间的长短是由程序设定的,不会释放锁标志。
wait方法调用后,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。
yield 方法使当前线程让出CPU占有权,但让出的时间是不可设定的。yield()也不会释放锁标志。
yield()方法对应了如下操作: 先检测当前是否有相同优先级的线程处于同可运行状态,如有,则把 CPU 的占有权交给此线程,否则继续运行原来的线程。所以yield()方法称为"退让",它把运行机会让给了同等优先级的其他线程。
sleep方法允许较低优先级的线程获得运行机会,但yield()方法执行时,当前线程仍处在可运行状态,所以不可能让出较低优先级的线程些时获得CPU占有权。 在一个运行系统中,如果较高优先级的线程没有调用 sleep 方法,又没有受到 I/O阻塞,那么较低优先级线程只能等待所有较高优先级的线程运行结束,才有机会运行。
yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。所以yield()只能使同优先级的线程有执行的机会。
wait()与notify()的关系与应用
看以下代码
public class WaitTest { public int flag=10; public static void main(String[] args) { WaitTest wait = new WaitTest(); new Thread(new Runnable(){ public void run(){ wait.method1(); } }).start(); new Thread(new Runnable(){ public void run(){ wait.method2(); } }).start(); } public void method1(){ System.out.println("method 1 is running"); try{ synchronized(this){ System.out.println("method 1 is into lock"); while(flag>0){ this.wait(); System.out.println("method 1 get notify"); } System.out.println("method 1 is out lock"); } }catch(InterruptedException e){ e.printStackTrace(); } System.out.println("method 1 is end"); } public void method2(){ System.out.println("method 2 is running"); while(flag>0){ try{ synchronized(this){ flag--; this.notify(); } Thread.sleep(100); }catch(InterruptedException e){ e.printStackTrace(); } } System.out.println("method 2 is end"); } } 输出: method 1 is running method 1 is into lock method 2 is running method 1 get notify method 1 get notify method 1 get notify method 1 get notify method 1 get notify method 1 get notify method 1 get notify method 1 get notify method 1 get notify method 1 get notify method 1 is out lock method 1 is end method 2 is end
上例中,线程1执行method1先获取对象锁,然后判断flag的值,如果flag>0,则wait等待,此时释放锁。因此线程2执行method2可以获取对象锁,并且每次在锁内执行flag--,然后执行notify()通知其他线程,接着释放锁。线程1获取notify信号后,先获取对象锁,然后沿着wait方法继续向下执行。
wait()方法与notify()必须要与synchronized(resource)一起使用。也就是wait与notify针对已经获取了resource锁的线程进行操作,从语法角度来说就是Obj.wait(),Obj.notify必须在synchronized(Obj){...}语句块内。从功能上来说wait()线程在获取对象锁后,主动释放CPU控制权,主动释放对象锁,同时本线程休眠。直到有其它线程调用对象的notify()唤醒该线程,才能继续获取对象锁,并继续执行。相应的notify()就是对对象锁的释放操作。
【因此,我们可以发现,wait和notify方法均可释放对象的锁,但wait同时释放CPU控制权,即它后面的代码停止执行,线程进入阻塞状态,而notify方法不立刻释放CPU控制权,而是在相应的synchronized(){}语句块执行结束,再自动释放锁。】
释放锁后,JVM会在等待resoure的线程中选取一线程,赋予其对象锁,唤醒线程,继续执行。这样就提供了在线程间同步、唤醒的操作。Thread.sleep()与Object.wait()二者都可以暂停当前线程,释放CPU控制权,主要的区别在于Object.wait()在释放CPU同时,释放了对象锁的控制,而在同步块中的Thread.sleep()方法并不释放锁,仅释放CPU控制权。