java会为每个object对象分配一个monitor,当某个对象的同步方法(synchronized methods )被多个线程调用时,该对象的monitor将负责处理这些访问的并发独占要求。
wait() 的方法是Object的方法,不是线程的方法,作用是让线程挂起,处于等待状态,之后可以调用notify()的方法激活线程。
也可以这样使用,线程处于运行时,判断到某个状态时调用wait(),这样线程处于等待状态,在其他地方调用object的notify的方法时,也必须获取到该线程的同步锁:
synchronized (object) {
boject.notify();
}
对于notify()方法,如果多个线程处于等待状态,那么被唤醒的线程由VM选择决定,调用了notify的线程将放弃对对象的锁,其他线程会尝试获得该对象的锁,获得该锁的对象将被唤醒:
notify()、wait()的方法必须要在获得锁的情况下使用,比如说在同步代码里面:
synchronized (object) {
boject.notify();
}
所以注意的是:
1.wait()与notify()的方法是object的共同属性,此时object当成一个同步锁。
2.wait()的方法会让线程挂起并释放锁,而notify()的方法会将挂起的线程唤醒同时在同步代码块结束后释放锁。
3.wait()与notify的方法是已经获取了锁的情况下,获取对象的monitor的方法有:
a.执行这个object的synchronized方法。
b.执行一段synchronized代码,并基于这个object的同步。
c.如果boject是class类,可以执行它的synchronized static 方法。
简单理解:wait()与notify()都是获取到同步锁的情况下才能执行的,语法上就是写在synchronized中。wait()的作用是放弃同步锁并使线程进入休眠,直到其他线程获取到同步锁使用notify()后才唤醒。Thread.sleep()与Object.wait()二者都可以暂停当前线程,释放CPU控制权,主要的区别在于Object.wait()在释放CPU同时,释放了对象锁的控制。
使用:
1.同步锁的理解
启动十个线程线程,代码如下:
public static void main(String[] args) {
Object a = new Object();
for (int i = 0; i < 10; i++) {
new Thread(new test2(a, i + "")).start();
}
}
public static class test2 implements Runnable {
Object lock;
String name;
public test2(Object lock, String name) {
this.lock = lock;
this.name = name;
}
public void run() {
System.out.println(name + "开始执行");
double f = 66;
while (f < 30000000.0) {
f = f + 0.05;
}
System.out.println(name + "结束执行");
}
}
执行结果如下:
2开始
0开始
7开始
4开始
6开始
8开始
3开始
1开始
5开始
9开始
8结束
5结束
4结束
0结束
2结束
6结束
3结束
1结束
7结束
9结束
总结:十个线程执行差不多是同时执行的,因为在循环过程中执行了耗时操作,所以所有线程执行了开始执行后才会执行结束执行操作,最先开始的不一定最先结束,因为是使用cup是随机抢占的。
加了同步锁:
public static class test2 implements Runnable {
Object lock;
String name;
public test2(Object lock, String name) {
this.lock = lock;
this.name = name;
}
public void run() {
synchronized (lock) {
System.out.println(name + "开始");
double f = 66;
while (f < 30000000.0) {
f = f + 0.05;
}
System.out.println(name + "结束");
}
}
}
执行结果如下:
0开始
0结束
4开始
4结束
3开始
3结束
2开始
2结束
1开始
1结束
总结:进行同步后,其他线程会等待已经获取到同步锁的线程完成操作并将同步锁释放,释放后线程随机去抢同步锁,获取到同步锁的线程才能执行。
让线程执行了开始后就调用wait():
public static class test2 implements Runnable {
Object lock;
String name;
public test2(Object lock, String name) {
this.lock = lock;
this.name = name;
}
public void run() {
synchronized (lock) {
System.out.println(name + "开始");
try {
//放弃锁并使当前线程休眠
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
double f = 66;
while (f < 30000000.0) {
f = f + 0.05;
}
System.out.println(name + "结束");
}
}
}
打印结果如下:
0开始
2开始
1开始
3开始
4开始
总结:所有线程都调用了wait()后暂停了,由于没有唤醒所以都没有执行下面的操作。
让其中一个线程唤醒其他线程:
public static class test2 implements Runnable {
Object lock;
String name;
public test2(Object lock, String name) {
this.lock = lock;
this.name = name;
}
public void run() {
synchronized (lock) {
System.out.println(name + "开始");
try {
//如果是第四个线程,唤醒其他的线程
if (name.equals("4")) {
lock.notifyAll();
//lock.wait();如果加了这个后,第四个线程不会执行下面的操作
} else {
// 放弃锁并使当前线程休眠
lock.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
double f = 66;
while (f < 30000000.0) {
f = f + 0.05;
}
System.out.println(name + "结束");
}
}
}
打印如下:
0开始
2开始
1开始
3开始
4开始
4结束
3结束
1结束
2结束
0结束
总结:唤醒其他线程后,那些线程将随机抢占同步锁执行下面的操作。值得注意的是,notify的方法是唤醒其他线程但是不会立即放弃同步锁,wait()是会立即放弃同步锁的。
转载注明出处:http://blog.youkuaiyun.com/u014614038/article/details/49020147