Java中提供了很多种方法对线程的状态进行控制以及线程之间的通信,包括wait、notify、notifyAll、sleep,下面我们就来看一下它们之间有什么区别,以及如何使用这些方法进行线程状态的控制与通信。
例题:
使用两个线程打印 1-100。线程1, 线程2 交替打印
public class Number implements Runnable {
private int number =1;
Object obj = new Object();
@Override
public void run() {
synchronized (this) {
while(number<100){
this.notify();
System.out.println(Thread.currentThread().getName()+number);
number++;
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class test5{
public static void main(String[] args) {
Number number = new Number();
Thread t1= new Thread(number);
Thread t2 = new Thread(number);
t1.setName("数字一");
t2.setName("数字二");
t1.start();
t2.start();
}
}
sleep ()和wait()方法
一:继承自哪个类
sleep是Thread
类的方法,导致此线程暂停执行指定时间,给其他线程执行机会,但是依然保持着监控状态,过了指定时间会自动恢复,调用sleep方法不会释放锁对象。
所以sleep()方法是不会造成线程间通信的
当调用sleep方法后,当前线程进入阻塞状态。目的是让出CPU给其他线程运行的机会。但是由于sleep方法不会释放锁对象,所以在一个同步代码块中调用这个方法后,线程虽然休眠了,但其他线程无法访问它的锁对象。这是因为sleep方法拥有CPU的执行权,它可以自动醒来无需唤醒。而当sleep()结束指定休眠时间后,这个线程不一定立即执行,因为此时其他线程可能正在运行。wait方法是Object类里的方法,
当一个线程执行到wait()
方法时,它就进入到一个和该对象相关的等待池
中,同时释放了锁对象,
等待期间可以调用里面的同步方法,其他线程可以访问,等待时不拥有CPU的执行权
,否则其他线程无法获取执行权。
当一个线程执行了wait方法后
,必须调用notify或者notifyAll方法才能唤醒
,而且是随机唤醒,
若是被其他线程抢到了CPU执行权,该线程会继续进入等待状态。由于锁对象可以时任意对象,所以wait方法必须定义在Object类中,因为Obeject类是所有类的基类。
二:是否可以传入参数
-
sleep()方法必须传入参数,参数就是休眠时间,时间到了就会自动醒来。
-
wait()方法可以传入参数也可以不传入参数,传入参数就是在参数结束的时间后开始等待,不穿如参数就是直接等待。
三.作用范围
-
- wait()、notify()和notifyAll()方法
只能在同步方法或者同步代码块中使用,
- wait()、notify()和notifyAll()方法
-
- wait()、notify()和notifyAll()三个方法的调用着必须是同步代码块或同步方法的同步监视器
-
否则 1 ,2 都会报
java.lang.IllegalMonitorStateException
异常 -
而
sleep方法可以在任何地方使用
但是注意sleep是静态方法,也就是说它只对当前对象有效。通过对象名.sleep()想让该对象线程进入休眠是无效的,它只会让当前线程进入休眠。
四.调用者的区别
- 首先为什么wait、notify和notifyAll方法要和synchronized关键字一起使用?
- 因为wait方法是使一个线程进入等待状态,并且释放其所持有的锁对象,notify方法是通知等待该锁对象的线程重新获得锁对象,然而如果没有获得锁对象,wait方法和notify方法都是没有意义的,因此必须先获得锁对象再对锁对象进行进一步操作于是才要把wait方法和notify方法写到同步方法和同步代码块中了。
总结区别(面试题)
sleep()和 wait ()的异同:
相同点:一旦执行方法,都可以使当前线程进入阻塞状态
不同点:
- 1.继承位置:
Thread类声明 sleep(),Object 类声明wait()
- 2 调用的位置不同:
sleep()可以再任何场景下调用,wait()必须在同步代码块中调用
- 关于是否释放同步监视器:
如果两个方法都使用在同步代码块或者同步方法中,sleep()不会释放锁,wait()会释放锁。