sleep方法
这方法理解起来简单,使用也简单。作用是让当前线程休眠指定的时间,也就是暂停当前线程。sleep方法是个Thread类的静态方法,可以在任意的地方执行。
public static native void sleep(long millis) throws InterruptedException;
进入源码看看这方法,有一个native关键字,这关键字是jni(Java Native Interface 实现Java层与C/C++层之间的通讯)标识,这里不多讲述。使用这sleep方法要自行抛出异常。这方法通常用于延迟执行代码。
比如。
try{
Thread.sleep(2000);
//2秒后执行的代码
}catch(InterruptedException e){
}
或者作为定时器
while(true){
try{
Thread.sleep(2000);
//每2秒后执行的代码
}catch(InterruptedException e){
}
}
wait、notify方法
这两个方法其实是一对的,从名字来看一个等待,一个唤醒。上面提到的sleep方法是自动唤醒自己,而wait是一直等待,等着notify唤醒。进入源码,查看这两个方法,会发现这两个方法并不是Thread类的,而是Object类的方法。而且都是用native关键字修饰,意味着这也是jni通信。
class Object {
public final native void wait(long timeout) throws InterruptedException;
public final native void notify();
...
}
这两个方法主要是用于线程的锁。之前说过锁可以是任意对象,所以wait、notify方法就是锁的方法。官方API文档描述notify方法是唤醒在此对象监视器(锁)上等待的单个线程,wait方法在其他线程调用此对象的 notify方法,导致当前线程等待。还有一个notifyAll方法,意思是notify方法等待的所有线程。
用例子说话。
final Object obj = new Object();
new Thread() {
public void run() {
synchronized (obj) {
System.out.println("wait before");
try {
obj.wait();
} catch (InterruptedException e) {
}
System.out.println("wait after");
}
}
}.start();
try {
Thread.sleep(1000);
System.out.println("延迟1秒");
synchronized (obj) {
obj.notify();
}
} catch (InterruptedException e) {
}
输出为
wait before
延迟1秒
wait after
使用这两个方法要注意的是监视器(锁)必须是一致,而且要synchronized同步。否则抛出IllegalMonitorStateException。
interrupt方法
上一节讲到,线程阻塞而无法执行下面代码,这是就要用到interrupt方法。
Thread thread = new Thread() {
public void run() {
try {
obj.sleep(10000);//可以用wait代替,但是别忘了同步锁
} catch (InterruptedException e) {
}
System.out.println("go");
}
};
thread.start();
thread.interrupt();
原来要等待10秒执行打印,使用interrupt就可以清除阻塞。
join方法
join方法是等待该线程终止,意味着不往下面语句执行,直接中断。从源码上分析,其实是wait方法,一直阻塞。
public void join(){
...
while (isAlive()) {
wait(0);
}
...
}
来个例子。
Thread thread1 = new Thread() {
public void run() {
try {
Thread.sleep(1000);
System.out.println("1 run before");
join();//执行上面的语句就永久睡眠
System.out.println("1 run");//不再执行
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread1.start();//thread1先执行
Thread thread2 = new Thread() {
public void run() {
try {
Thread.sleep(5000);//延迟5秒打印
System.out.println("2 run");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
try {
Thread.sleep(1000);//thread2延迟1秒启动
thread2.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
上面的例子是thread1线程执行比thread2线程要先,thread1会完成join方法之前的语句,不再执行join方法后面的语句。其实可以把join方法当作一直不醒的wait方法。
yield方法
yieId方法作用是暂停当前正在执行的线程对象,并执行其他线程。yieId与join方法区别在于是否还往下执行语句。yieId不带任何参数,而且暂停的触发时间不准确。
Java多线程基础系列就讲到这里。作者初写文章,写作能力还待提升,谢谢大家~