sleep()使当前线程进入停滞状态(阻塞当前线程),让出CUP的使用、目的是不让当前线程独自霸占该进程所获的CPU资源,以留一定时间给其他线程执行的机会,他不能改变对象的机锁,所以当在一个Synchronized块中调用Sleep()方法是,线程虽然休眠了,但是对象维持该锁有被释放,其他线程获取到该对象的锁(即使睡着也持有对象锁)。在sleep()休眠时间期满后,该线程不一定会立即执行,这是因为其它线程可能正在运行而且没有被调度为放弃执行,除非此线程具有更高的优先级。
Java 中线程之间的协作是通过Object 的wait()方法和notify()方法来实现的,当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,同时失去(释放)了对象的机锁(暂时失去对象锁,wait(long timeout)超时时间到后还需要返还对象锁);其他线程可以访问;
wait()和sleep()都可以通过interrupt()方法打断线程的暂停状态,从而使线程立刻抛出InterruptedException(但不建议使用该方法)。
wait()与sleep()的区别:
1)sleep()方法是Thread 类的方法,而wait()方法是Object 的方法。
2)sleep()方法并不会释放对象的锁,而wait()方法的调用却释放对象的锁,可以通过notify()或notifyAll()方法可以再次获得对象的锁。
接着,简单介绍下wait()方法:
1)wait()方法与sleep()方法一样,可以接受一个毫秒数,当今过指定的时间之后对象将再一次的获得锁。
2)wait(),notify()和notifyAll()必须在同步控制方法或同步控制块中进行调用,否则将会抛出IllegalMonitorStateException异常。
3)在使用wait()方法时,应该将它嵌套在while 语句中,防止线程的意外唤醒(notifyAll 方法)。
代码块如下
synchronized(obj1) //1.进入同步块
{
try {
...
obj1.wait(); //2.进入暂停状态
}catch (InterruptedException exp) {}
}
1.当前同步对象(monitor)为obj1,obj1是任一实例,若是同步方法,则同步对象是this.进入同步块后,obj1为锁定状态,锁定状态 对obj1本身无任何影响,而其它线程执行到同一代码时,因不能获得锁,处于Block状态,一旦解锁,被block的线程自动继续执行.
2.调用obj1.wait()有两个作用,一是使线程进入等待状态,二是解锁obj1,这时被block的线程将获得锁.线程1要退出等待必须要由其它线程显式的调用obj1.notify()或notifyAll()方法.
如
synchronized(obj1)
{
...
obj1.notify(); //3. 向wait的线程发通知信息
...
}
若其它线程执行到此时,线程1处于wait状态,则wait状态解除,解除后,若线程1若得到锁就能继续执行,若有多个线程处于obj1的wait状态,notify将随机选一个线程激活,而notifyAll是同时解除所有的wait状态.
如果在同步块入口点阻塞,不须其它线程调用notify(),调了也没效果,同步块能自动获得锁
如果是wait造成了阻塞,须用notfiy()激活,这两个方法是配合使用
下面用具体的例子
package com.test;
import java.text.SimpleDateFormat;
import java.util.Date;
public class threadTest {
public void waitFunction(){
synchronized(this) //1.进入同步块
{
try{
System.out.println( "进入waitFunction" );
this.wait(); //2.进入暂停状态
System.out.println( "退出waitFunction" );
}catch (InterruptedException exp){
}
}
}
public void notifyFunction(){
synchronized(this) //1.进入同步块
{
System.out.println( "进入notifyFunction" );
this.notify(); //2.
System.out.println( "退出notifyFunction" );
}
}
public void sleepFunction(){
synchronized(this) //1.进入同步块
{
try{
System.out.println( "进入sleepFunction" );
Thread.sleep( 9000 ); //2.进入暂停状态
System.out.println( "退出sleepFunction" );
}catch (InterruptedException exp){
}
}
}
public static void main(String args[]){
final threadTest tt= new threadTest();
final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
new Thread(){ public void run(){
System.out.println( "线程1 sleepFunction()"+df.format(new Date()));
tt.sleepFunction();
} }.start(
);
new Thread(){ public void run(){
System.out.println( "线程2 waitFunction()"+df.format(new Date()) );
tt.waitFunction();
} }.start(
);
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Thread(){ public void run(){
System.out.println( "线程3 notifyFunction()"+df.format(new Date()) );
tt.notifyFunction();
} }.start(
);
}
}
线程1 sleepFunction()2013-03-28 15:24:45
线程2 waitFunction()2013-03-28 15:24:45
进入sleepFunction
退出sleepFunction
进入waitFunction
线程3 notifyFunction()2013-03-28 15:25:05
进入notifyFunction
退出notifyFunction
退出waitFunction
结果分析:
(1):线程1执行时的sleepFunction,因sleep是要维持对象锁,其他线程无法访问其他的同步块。
(2):线程2执行的waitFunction,当执行waitFunction时,sleep维持对象锁,所以无法执行同步块,直到sleep释放对象锁【即休眠时间过了,并执行相关代码】,才进入waitFunction同步块中,因此前面五步输出
线程1 sleepFunction()2013-03-28 15:24:45
线程2 waitFunction()2013-03-28 15:24:45
进入sleepFunction
退出sleepFunction
进入waitFunction
(3):线程2执行 wait方法后,将释放锁资源,并进入等待状态,线程3执行的时候因线程2已经释放锁资源,因此就能进入同步块中,并执行notify方法,将wait状态线程唤醒,让wait线程完成继续的工作。这是为啥后4步输出为
线程3 notifyFunction()2013-03-28 15:25:05
进入notifyFunction
退出notifyFunction
退出waitFunction