在多线程中使线程阻塞有那么几种情况:
- sleep()的调用
- wait()的调用
- 遇到阻塞io
- suspend使线程暂停执行(这个方法已弃用)
- 在未持有锁时,进入同一个对象锁的同步代码块时,等待锁的时候。
那么我们这篇文章就看一看sleep()和wait()分别都能干什么。
sleep()
Thread.sleep(long millis),可以使当前线程休眠指定的毫秒数。但是需要注意的是,调用该方法并不会释放锁,我们通过代码来看:
class T extends Thread{
@Override
synchronized public void run() {
for(int i = 0; i < 10; i++){
System.out.println(Thread.currentThread().getName() + ": " + i);
if(i == 5){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class Test {
public static void main(String[] args){
T t = new T();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
}
}
结果:
线程1: 0
线程1: 1
线程1: 2
线程1: 3
线程1: 4
线程1: 5 // 这里虽然线程暂停了执行,但是线程2并没有抢到执行权
线程1: 6
线程1: 7
线程1: 8
线程1: 9
线程2: 0
线程2: 1
线程2: 2
线程2: 3
线程2: 4
线程2: 5
线程2: 6
线程2: 7
线程2: 8
线程2: 9
运行得知,该代码中虽然在i==5的时候,使线程sleep了,但是,线程并没有释放锁,所以该代码还是同步执行的。
wait()
这个方法可以带上参数或者不带参数,不带参数的时候需要手动显示的去notify(),才可以将该线程唤醒,在这之前线程是一直阻塞的,而带参数的话是在一段时间内,如果都没有将该线程唤醒,则会自动唤醒该线程,这里我们使用带参数的wait方法:
class T extends Thread{
@Override
synchronized public void run() {
for(int i = 0; i < 10; i++){
System.out.println(Thread.currentThread().getName() + ": " + i);
if(i == 5){
try {
wait(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class Test {
public static void main(String[] args){
T t = new T();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
}
}
结果:
线程1: 0
线程1: 1
线程1: 2
线程1: 3
线程1: 4
线程1: 5 // 这里可以看出,线程立马释放了锁,让线程2抢到了执行权
线程2: 0
线程2: 1
线程2: 2
线程2: 3
线程2: 4
线程2: 5
线程2: 6
线程2: 7
线程2: 8
线程2: 9
线程1: 6
线程1: 7
线程1: 8
线程1: 9