线程通信
通过加锁的方式保证共享数据访问的完整性,但是并没有规定线程执行的先后顺序。至于,各线程到底谁先执行由操作系统的调度所决定。
在进行多线程程序设计时,还会遇到另一类问题**:如何控制相互交互的线程之间的运行顺序,即多线程间的同步。**
API常用方法
Java通过Object类的wait、nofify、notifyAll方法实现线程间的通信。由于锁可以是任意对象,所以这些方法都定义在Object类中。
wait( )
使当前线程放弃同步锁并进入到等待,直到其它线程进入此同步锁并调用notify()或notifyAll()方法唤醒该线程为止
notify( )
唤醒此同步锁上等待的第一个调用wait()方法的线程。
notifyAll( )
唤醒此同步锁上调用wait( )方法的所有线程
注意
**wait( )、 notify( )、notifyAll( )**这三个方法的调用者都应该是同步锁对象;否则JVM抛出IllegalMonitorStateException异常。
此处为接口实现类 以及 重写的run方法:
synchronized(同步) 是wait(等待) 和 notify(通知) 能使是数据同步的关键
Thread01(t1) and Thread02(t2) Running together one by one wait and notify
t1 wait ----->running ----->finished------->notify--------->wait
t2 --------->t2 notify ------>wait ------->back running ->finished
package com.etime809;
import java.util.concurrent.locks.ReentrantLock;
public class RunnableImpl01 implements Runnable {
private int number = 1;
private ReentrantLock reentrantLock = new ReentrantLock();
@Override
public void run() {
while (true) {
/**
* synchronized 是wait 和 notify 能使是数据同步的关键
* Thread01(t1) and Thread02(t2) Running together one by one wait and notify
*
* t1 wait ----->running ----->finished------->notify--------->wait
* t2 --------->t2 notify ------>wait ------->back running ->finished
*/
synchronized (reentrantLock) {
reentrantLock.notify();
if (number <= 100) {
String name = Thread.currentThread().getName();
System.out.println(name + "当前线程正在打印:" + number++);
try {
reentrantLock.wait();
} catch (Exception e) {
e.printStackTrace();
}
} else {
break;
}
}
}
}
}
此处为main函数测试文件
package com.etime809;
public class RunnableTest01 {
public static void main(String[] args) {
RunnableImpl01 runnableImpl01 = new RunnableImpl01();
Thread t1 = new Thread(runnableImpl01,"线程①");
Thread t2 = new Thread(runnableImpl01,"线程②");
Thread t3 = new Thread(runnableImpl01,"线程③");
Thread t4 = new Thread(runnableImpl01,"线程④");
Thread t5 = new Thread(runnableImpl01,"线程⑤");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
小 结
1、 调用wait()进入阻塞状态并且释放锁
2、 调用notify()唤醒阻塞的线程
3、 流程与理解:线程1打印数字后执行lock.wait()方法线程1进入阻塞状态并释放锁;线程2进入run方法后调用notify()唤醒阻塞的线程1,线程1继续执行直至完成;当线程2打印数字后执行lock.wait()方法线程2进入阻塞状态并释放锁…依次类推
4、 锁、锁.wait()、锁.nofity()这三处必须是同一个锁(监视器)
案例(Producer && Consumer && Test && BankCard)
这是一个比较简单的wait() 和notify() 的例子 帮助我们更好的理解线程通信的应用
package com.etime809;
/**
* 银行卡类
* BankCard
*/
public class BankCard {
private String number;
private double money;
private String message;
public BankCard() {
}
public BankCard(String number, double money, String message) {
this.number = number;
this.money = money;
this.message = message;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
package com.etime809;
/**
* 消费者 Consumer Runnable实现类
*/
public class ConsumerRunnable implements Runnable {
private BankCard bankCard;
public ConsumerRunnable() {
}
public ConsumerRunnable(BankCard bankCard) {
this.bankCard = bankCard;
}
@Override
public void run() {
while (true) {
synchronized (bankCard) {
if (bankCard.getMoney() > 0) {
String message = bankCard.getMessage();
System.out.println(message + "取了:" + bankCard.getMoney());
bankCard.setMoney(0);
bankCard.notify();
} else {
try {
bankCard.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
package com.etime809;
/**
* 生产者producer runnable 实现类
*/
public class ProducerRunnable implements Runnable {
private int counter = 0;
private BankCard bankCard;
public ProducerRunnable() {
}
public ProducerRunnable(BankCard bankCard) {
this.bankCard = bankCard;
}
@Override
public void run() {
while (true) {
synchronized (bankCard) {
if (bankCard.getMoney() <= 0) {
if (counter % 2 == 0) {
bankCard.setMessage("父亲给你打钱了!");
bankCard.setMoney(2000);
} else {
bankCard.setMessage("母亲给你打钱了!");
bankCard.setMoney(4000);
}
counter++;
bankCard.notify();
} else {
try {
bankCard.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
package com.etime809;
public class ProducerConsumerTest {
public static void main(String[] args) {
BankCard bankCard = new BankCard("666666", 10, "开户成功!");
ProducerRunnable producerRunnable = new ProducerRunnable(bankCard);
ConsumerRunnable consumerRunnable = new ConsumerRunnable(bankCard);
Thread t1 = new Thread(producerRunnable);
Thread t2 = new Thread(consumerRunnable);
t1.start();
t2.start();
}
}