在上节中,介绍了java多线程中同步锁的概念,synchronized方法和synchronized代码块都是为了解决线程并发的问题,同一时间允许一个线程访问当前类或者对象。如果涉及到线程间的协作通信,就需要用到wait、notify、notifyAll方法,这三个方法是Object的方法。也就是任何对象都具有这三个方法,在java中wait、notify、notifyAll要放在synchronized方法中或者synchronized代码块中使用。从功能上来说,wait方法在线程获得对象锁之后,主动释放掉对象锁,并且休眠当前线程。直到有线程调用notify方法之后,他才会继续获得对象锁执行当前线程。notify方法就是用来唤醒对象锁的,但是notify执行完之后并不是马上执行当前唤醒的线程,而是等当前线程正在执行的线程执行完之后再执行。wait方法和Thread的Sleep方法作用类似,都是暂停线程,释放cpu使用权。区别在于wait方法会释放掉锁,而sleep只是休眠当前对象,并不会让出对象锁。调用了wait的线程会一直等待,后面代码不会再执行,直到有其他线程调用notify或者notifyAll才会继续执行。notifyAll的作用是唤醒所有的休眠的线程,注意只是唤醒被wait的线程。实例如下:
package com.thread.test;
public class MainTestThread {
public static void main(String[] aa) {
final MainTestThread test = new MainTestThread();
//创建线程1
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
test.test1("线程1");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
//创建线程2
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
test.test1("线程2");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
//创建线程3
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try {
test.test1("线程3");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
//启动线程
thread.start();
thread1.start();
thread2.start();
}
public void test1(String thread) throws InterruptedException {
synchronized (this) {
for (int j = 1; j <= 5; j++) {
//当为1的时候,表示进来新线程
if (j == 1) {
System.out.println(thread + "进入");
}
//为3的时候,暂时当前线程,并且释放对象锁
if (j == 3) {
this.wait();
}
System.out.println(thread + "第" + j + "运行");
//唤醒该线程
this.notify();
}
}
}
}
运行结果如下:
但是也有出现这种情况:
最后一个线程执行了一半,这是因为notify在唤醒休眠线程的时候,是随机唤醒的。当线程1执行到3时,wait后,另一个线程进入,并且唤醒线程1。然后又执行线程1(线程的执行是无顺序的,不会因为你先调用就先执行某个线程),那么最后一个线程执行到3的时候,被休眠了。没有其他的线程来唤醒,一直等待下去。使用sleep来休眠当前执行线程:
package com.thread.test;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MainTestThread3 {
public static void main(String[] aa){
final MainTestThread3 test=new MainTestThread3();
Thread thread=new Thread(new Runnable() {
@Override
public void run() {
try {
test.test1("线程1");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread thread1=new Thread(new Runnable() {
@Override
public void run() {
try {
test.test1("线程2");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread thread2=new Thread(new Runnable() {
@Override
public void run() {
try {
test.test1("线程3");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
thread.start();
thread1.start();
thread2.start();
}
public void test1(String thread) throws InterruptedException{
SimpleDateFormat sim=new SimpleDateFormat("yyyyMMddHHmmssSS");
synchronized (this) {
for (int j = 1; j <= 5; j++) {
if(j==1){
System.out.println(thread+"进入");
}
if(j==3){
String data1=sim.format(new Date());
Thread.sleep(3000);
String data2=sim.format(new Date());
System.out.println("执行花费了:"+String.valueOf((Long.parseLong(data2)-Long.parseLong(data1))+"毫秒"));
}
System.out.println(thread+"第"+j+"运行");
}
}
}
}
执行结果: