wait notify 是Object对象中的方法,也就意味着任何类都具有这两个方法。使用wait和notify的前提是要先获取锁,因为wait和notify是针对某一把锁来操作的。
来看一个例子:
import java.util.concurrent.TimeUnit;
public class o1waitnotify {
public static void main(String [] args){
m4 a = new m4();
new Thread(a::m1).start();
new Thread(() -> {
while(true){
if(a.count == 3)
break;
}
System.out.println("中断了");
}).start();
}
}
class m4{
volatile int count = 0;
void m1(){
for(int i=0; i<5; i++){
this.count++;
System.out.println(this.count);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
以上程序使用volatile关键字然后保证了内存可见性能够正常停止线程,但是有一个问题,就是线程2中的while(true)死循环非常浪费cpu,有没有优雅一点的方法,比如我检测一次后没有到3那么我就先睡一会,然后当count+1的时候把我叫醒,然后我再判断一次,这样就大大提高了性能。
使用wait和notify
我们把代码改一下:
import java.util.concurrent.TimeUnit;
public class o1waitnotify {
public static void main(String [] args){
Object o = new Object();
m4 a = new m4();
new Thread(() -> {
synchronized (o) {
System.out.println("t2启动了!");
if(a.count != 5){
try {
o.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
o.notifyAll();
}
System.out.println("中断了");
}
}).start();
new Thread(() -> {
synchronized (o) {
for(int i=0; i<10; i++){
a.count++;
System.out.println("当前值为:"+a.count);
if(a.count == 5) {
o.notifyAll();
try {
o.wait(); //这里要让出锁,如果不让出,线程2还是不会执行,因为这个再循环体内,执行结束才会让出锁
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("唤醒线程!");
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
}
}
class m4{
volatile int count = 0;
}
wait()方法释放锁,notify()不释放锁
这样就比第一种方式好一些,那么有没有更好的方法呢?当然有,接下来我们介绍Latch(门栓),
内部有一个计数机制,当计数器为0的时候唤醒所有阻塞线程,当计数器大于0的时候进入阻塞状态。
把我们的程序改一下:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class o1waitnotify {
public static void main(String [] args){
Object o = new Object();
CountDownLatch latch = new CountDownLatch(1);
m4 a = new m4();
new Thread(() -> {
System.out.println("t2启动了!");
if(a.count != 5){
try {
latch.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("中断了");
}).start();
new Thread(() -> {
for(int i=0; i<10; i++){
a.count++;
System.out.println("当前值为:"+a.count);
if(a.count == 5) {
latch.countDown();
System.out.println("唤醒线程!");
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
}
class m4{
volatile int count = 0;
}
可以看到,我把synchronized去掉了,门栓不需要锁定任何对象。这样就比wait(),notify()方便很多了。