上次我们讲完了锁机制,接下来说一下sleep 和wait对锁的控制。
sleep方法是Thread类的静态方法,表示在指定的毫秒数内让当前正在执行的线程休眠。
wait方法则是Object类的普通方法,表示当前线程等待,直到其他线程调用这个对象的notify()或者notifyAll()方法。
正如在上文中所说的, java引入了同步监视器来解决线程同步问题,使用同步监视器的通用方法就是同步代码块。其语法格式如下:
|
synchronized (obj)
{
}
|
其中obj就是同步监视器,上面代码的含义是:线程开始执行同步代码块之前,必须先获得对同步监视器的锁定。任何时候只能有一条线程可以获得对同步监视器的锁定。同步代码执行结束后,该线程自然释放了对同步监视器的锁定。
因为wait会对线程的同步监视器进行操作,所以它们必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-synchronized block中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常。
sleep和wait具有使当前线程沉睡的作用,最为重要的一个区别就是sleep是Thread类的静态方法,因此他不能改变对象的锁。 所以当在一个Synchronized方法中调用sleep()时,线程虽然休眠了,但是对象的锁没有被释放,其他线程仍然无法访问这个对象。而wait()方法则会在线程休眠的同时释放掉机锁,其他线程可以访问该对象。
下面我们通过一个例子,来深入了解一下:
|
/**
* Thread sleep和wait区别
* @author liubing
*
*/
public class TestSleepAndWait implements Runnable
{
int number =
10;
public void firstMethod() throws Exception
{
synchronized ( this)
{
number +=
100;
System. out.println( number);
}
}
public void secondMethod() throws Exception
{
synchronized ( this)
{
/**
* (休息2S,阻塞线程)
* 以验证当前线程对象的机锁被占用时,
* 是否被可以访问其他同步代码块
*/
//Thread.sleep(2000);
this.wait(2000);
number *=
200;
}
}
@Override
public void run()
{
try {
firstMethod();
} catch (Exception
e) {
e.printStackTrace();
}
}
public static void main(String[]
args) throws Exception {
TestSleepAndWait testSleepAndWait = new TestSleepAndWait();
Thread thread = new Thread(testSleepAndWait);
thread.start();
testSleepAndWait.secondMethod();
}
}
|
你能猜出打印的number值是多少吗?
当使用 this.wait(2000) 时,打印的number值是 110
当使用 Thread.sleep(2000)时,打印的number值是2100
简单分析一下代码:
这个类有两个同步方法,也就是任何一个方法执行时,TestSleepAndWait类的对象都会被锁定,导致其他方法等待。
1. 我们先来看使用wait方式时的情况:
主线程main方法开始执行, 调用thread.start()方法时,线程进入就绪状态,等待cpu调度。接下来会调用TestSleepAndWait类的secondMethod()方法,该方法的执行会先于thread的run方法。
因此,当secondMethod()方法调用时,testSleepAndWait对象首先被main线程锁定,随后主线程进入等待。由于wait方法会使得main线程释放对testSleepAndWait对象的锁定,因此thread线程获得对testSleepAndWait对象的锁定,得到执行机会,run方法开始执行,number初始值10,加上100后,打印出110.
2. 再来看使用sleep方式时的情况:
主线程main方法开始执行, 调用thread.start()方法时,线程进入就绪状态,等待cpu调度。接下来会调用TestSleepAndWait类的secondMethod()方法,该方法的执行会先于thread的run方法。
因此,当secondMethod()方法调用时,testSleepAndWait对象首先被main线程锁定,随后主线程进入等待。由于sleep方法仍然保持对testSleepAndWait对象的锁定,因此thread线程虽然处于就绪状态,但是由于无法获得对testSleepAndWait对象的锁定,firstMethod()无法执行。
两秒钟后,main线程继续执行secondMethod()方法,number乘以200变成2000.
secondMethod()方法执行完毕,对象锁被释放。
此时thread线程终于获得对testSleepAndWait对象的锁定,开始执行firstMethod(),打印出2100.
不知道你看明白了没有。

本文深入解析Java线程同步机制中的sleep和wait方法,详细对比两者在控制线程休眠和释放锁方面的区别,并通过实例代码演示实际应用。
262





