sleep方法是Thread类的一个静态方法,该方法可以把当前正在运行的线程挂起一段时间(时间值由参数传入),挂起时间到期后,JVM会在适当的时间再次唤醒该线程。
先看一个例子代码:
package com.milihua.threaddemo;
public class SleepDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Thread thread = new Thread(new MyRunner());
//调用start方法启动线程
thread.start();
//
try {
//主线程挂起1000毫秒
System.out.println(Thread.currentThread().getName()+ "休眠1秒!");
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}MyRunner类代码:
package com.milihua.threaddemo;
public class MyRunner implements Runnable {
@Override
public void run() {
// 在线程中执行的代码
for( int i = 0; i<100; i++ ) {
System.out.println("MyRunner:" + i);
try {
System.out.println(Thread.currentThread().getName()+ "休眠0.5秒!");
//子线程挂起500毫秒
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}在SleepDemo类主线程中,启动子线程后,应用Thread类的sleep方法将主线程挂起1000毫秒,因为sleep方法抛出InterruptedException异常,因此调用sleep方法时,需要包含在try-cahtch语句,用于捕获sleep方法可能抛出的异常;在MyRunner类子线程中,每次循环都会调用Thread类的sleep方法将子线程挂起500毫秒,然后再继续执行。程序输出结果如下图所示:

图 15-8 SleepDemo输出结果
从输出结果可以看出,主线程在子线程执行之前就被挂起,也验证了线程调用start方法后,JVM并没有直接启动子线程,而是在主线程执行完后再执行子线程的。子线程在执行过程中,每次循环都会等待0.5秒后再继续执行。
上面的例子代码让我们了解了sleep的具体用法,那么sleep方法的具体应用场景是什么?实际应用编程中,在什么情况下需要使用sleep方法呢?
考虑一个编程任务。要求模拟一个服务器端文档上传服务程序,10个用户并发上传不同格式的文档,该服务程序需要启动一个转换线程把用户上传的文档统一转换为PDF文档,转换完成后,需要将该文档存储路径设置到文档对象中,并输出该文档信息。另外,模拟程序不需要处理实际的文档,模拟处理过程即可。
既然是服务器端处理程序,需要采用多线程处理,对每个用户的上传请求创建一个线程A,在线程A中,考虑到文档格式转换操作时间较长,需要创建一个转换文档格式的线程B。程序处理框架如下图所示:

图 15-9 文档上传服务程序处理过程
用户发出上传文档请求,主服务线程接收到请求后,创建一个处理该文档的A线程,A线程启动后,创建一个文档转换线程B,B线程负责文档格式的转换工作,A线程需要等待B线程完成文档转换工作后,存储并输出文档信息。上述过程涉及到A线程和B线程的同步,A线程创建B线程后,需要等待B线程完成工作,才能继续执行。此时,A线程就可以调用sleep方法休眠一段时间,等待B线程完成工作。
(1)首先建立Document类,该类有两个属性,分别是docName、savePath,savePath属性值的设置在B线程进行。代码如下:
package com.milihua.document;
public class Document {
String docName;
String savePath;
public Document(String inName)
{
this.docName = inName;
}
public String getDocName() {
return docName;
}
public void setDocName(String docName) {
this.docName = docName;
}
public String getSavePath() {
return savePath;
}
public void setSavePath(String savePath) {
this.savePath = savePath;
}
}(2)建立文档转换线程类(B线程),该类通过for循环模拟长时间处理操作,并设置传入doc对象的savePath属性,表示文档转换完成。代码如下:
package com.milihua.document;
public class Convert implements Runnable{
Document doc;
public Document getDoc() {
return doc;
}
public void setDoc(Document doc) {
this.doc = doc;
}
@Override
public void run() {
// TODO Auto-generated method stub
//模拟长时间处理操纵
System.out.println(doc.getDocName());
for(int i = 0; i < 100000; i++)
{
;
}
doc.setSavePath(doc.getDocName() + "_path");
}
}(3)建立请求处理线程类(A线程),该类启动文档转换线程,并调用sleep方法自身休眠1000毫秒,等待文档转换工作的完成。
package com.milihua.document;
public class Process implements Runnable{
Document doc;
public Document getDoc() {
return doc;
}
public void setDoc(Document doc) {
this.doc = doc;
}
@Override
public void run() {
// TODO Auto-generated method stub
Convert convert = new Convert();
convert.setDoc(doc);
Thread thread = new Thread(convert);
//调用start方法启动线程
thread.start();
while(true)
{
try {
Thread.sleep(1000);
if( !doc.getSavePath().equals("") )
{
System.out.println(doc.getDocName() + "处理完成,存储路径为:" + doc.getSavePath() );
return;
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
}
}
}(4)建立主线程类,该类首先初始化文档列表,然后启动线程对每个文档进行处理。
package com.milihua.document;
import java.util.ArrayList;
public class DocumentServer {
public static void main(String[] args) {
// TODO Auto-generated method stub
DocumentServer docServer = new DocumentServer();
ArrayList<Document> array = new ArrayList<Document>();
docServer.InitDocument(array);
for(int i = 0; i < array.size(); i++ )
{
Process pro = new Process();
pro.setDoc(array.get(i));
Thread thread = new Thread(pro);
thread.start();
}
}
public void InitDocument(ArrayList<Document> inArray)
{
for( int i = 0;i < 10; i++ )
{
Document temp = new Document("文档" + String.valueOf(i));
inArray.add(temp);
}
}
}程序输出结果如下图所示:

图 15-10 文档处理程序输出结果
■ 知识点拨
当线程需要等待资源或者信号到达才能继续执行时,可以采用sleep方法让线程自身休眠等待资源和信号。当线程唤醒时,需要线程自身判断等待的资源是否满足或信号是否到达,当资源仍然不能满足或信号仍未到达时,需要提供一种持续等待的机制,直到资源满足或信号到达。