Java再学习——sleep(), wait(), notify(), notifyAll()
首先一点就是Thread.sleep(long millis)方法是Thread类的静态方法,其他三个wait(), notify()和notifyAll()都是Object类的方法。
sleep(long millis)方法的调用能使当前线程暂定执行指定时间(但是并没有释放任何锁),然后再继续运行。相当于设个闹钟然后睡觉,要么时间到被闹钟叫醒,要么就被interrupt()叫醒,然后继续干活。
wait()方法则是让当前线程放弃调用wait()方法的对象的锁同时进入等待锁状态,然后只有通过该对象的notify()和notifyAll()方法才可以重新让线程进入抢夺状态。
notify()方法则是唤醒某个等待中的线程(任意的,没有规律可寻)进入抢夺状态。
notifyAll()方法则是唤醒所有等待中的线程进入抢夺状态。
完整消费者例子如下:
public class APP {
public static void main(String[] args) throws Exception {
class User {
private int value;
public User(int v) {
this.value = v;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
class Consumer extends Thread {
private User user;
public Consumer(User s) {
user = s;
}
@Override
public void run() {
while (true) {
try {
synchronized (user) {
user.wait();
System.out.println("in " + getName()
+ " ,value -> " + user.getValue());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Productor extends Thread {
private User user;
private int count = 0;
public Productor(User s) {
user = s;
}
@Override
public void run() {
while (true) {
try {
synchronized (user) {
int value = count++;
System.out.println("productor value is " + value);
user.setValue(value);
user.notify();
}
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
User user = new User(10);
Consumer consumer1 = new Consumer(user);
consumer1.start();
Consumer consumer2 = new Consumer(user);
consumer2.start();
Consumer consumer3 = new Consumer(user);
consumer3.start();
Productor productor = new Productor(user);
productor.start();
}
}
代码说明:
1,要wait和notify的对象,最好是个Javabean,基本数据类型和被处理过的String等,都不适合做这种多线程处理,因为这些存在赋值操作的变量,会让线程莫名的失去本以为理所当然的Monitor,而实际上都已经丢失了,当然就会报错java.lang.IllegalMonitorStateException,而只有操作对象本身就保证了只有一个Monitor,关键是看谁拿了而已。
2,基于第一点,所以在操作该对象时必须要进行同步,也就是要保证当前对其的操作时,你是独立占有它的。如例子中用的synchronized关键字对user进行代码块同步。
3,同步的时候一定要记得限定同步的范围,比如例子中如果把synchronized代码块包括到while层,如果放在Consumer类还好写,但是如果放在Productor类,那个就没有任何意义了,因为这样会使得当前线程一直占有该对象,别的对象就只有一直等待了。所以一定要在处理完后记得放开它。
4,notifyAll会唤醒所有的wait线程,但是并不一定就会 一起运行,还是要看线程个人造化。