1. 等待唤醒机制(线程之间的通信)
一个线程生产,一个线程消费,不能连续生产,不能连续消费 -> 等待唤醒机制(生产者,消费者)(线程之间的通信)
方法 | 说明 |
---|---|
void wait() | 线程等待,等待的过程中线程会释放锁,需要被其他线程调用notify方法将其唤醒,重新抢锁执行 |
void notify() | 线程唤醒,一次唤醒一个等待线程;如果有多条线程等待,则随机唤醒一条等待线程 |
void notifyAll() | 唤醒所有等待线程 |
wait和notify方法需要锁对象调用,所以需要用到同步代码块中,而且必须是同一个锁对象
2. 等待唤醒案例实现
/*
count和flag可以定义成包装类
但是要记得给count和flag手动赋值
不然对于本案例来说,容易出现空指针异常
*/
public class BaoZiPu {
//代表包子的count
private int count;
//代表是否有包子的flag
private boolean flag;
public BaoZiPu() {
}
public BaoZiPu(int count, boolean flag) {
this.count = count;
this.flag = flag;
}
/*
getCount 改造成消费包子方法
直接输出count
*/
public void getCount() {
System.out.println("消费了..............第"+count+"个包子");
}
/*
setCount 改造成生产包子
count++
*/
public void setCount() {
count++;
System.out.println("生产了...第"+count+"个包子");
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
public class Product implements Runnable{
private BaoZiPu baoZiPu;
public Product(BaoZiPu baoZiPu) {
this.baoZiPu = baoZiPu;
}
@Override
public void run() {
while(true){
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (baoZiPu){
//1.判断flag是否为true,如果是true,证明有包子,生产线程等待
if (baoZiPu.isFlag()==true){
try {
baoZiPu.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//2.如果flag为false,证明没有包子,开始生产
baoZiPu.setCount();
//3.改变flag状态,为true,证明生产完了,有包子了
baoZiPu.setFlag(true);
//4.唤醒消费线程
baoZiPu.notify();
}
}
}
}
public class Consumer implements Runnable{
private BaoZiPu baoZiPu;
public Consumer(BaoZiPu baoZiPu) {
this.baoZiPu = baoZiPu;
}
@Override
public void run() {
while(true){
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (baoZiPu){
//1.判断flag是否为false,如果是false,证明没有包子,消费线程等待
if (baoZiPu.isFlag()==false){
try {
baoZiPu.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//2.如果flag为true,证明有包子,开始消费
baoZiPu.getCount();
//3.改变flag状态,为false,证明消费完了,没 有包子了
baoZiPu.setFlag(false);
//4.唤醒生产线程
baoZiPu.notify();
}
}
}
}
public class Test01 {
public static void main(String[] args) {
BaoZiPu baoZiPu = new BaoZiPu();
Product product = new Product(baoZiPu);
Consumer consumer = new Consumer(baoZiPu);
Thread t1 = new Thread(product);
Thread t2 = new Thread(consumer);
t1.start();
t2.start();
}
}
3. 用同步方法改造等待唤醒案例
/*
count和flag可以定义成包装类
但是要记得给count和flag手动赋值
不然对于本案例来说,容易出现空指针异常
*/
public class BaoZiPu {
//代表包子的count
private int count;
//代表是否有包子的flag
private boolean flag;
public BaoZiPu() {
}
public BaoZiPu(int count, boolean flag) {
this.count = count;
this.flag = flag;
}
/*
getCount 改造成消费包子方法
直接输出count
*/
public synchronized void getCount() {
//1.判断flag是否为false,如果是false,证明没有包子,消费线程等待
if (this.flag == false) {
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//2.如果flag为true,证明有包子,开始消费
System.out.println("消费了..............第" + count + "个包子");
//3.改变flag状态,为false,证明消费完了,没 有包子了
this.flag = false;
//4.唤醒生产线程
this.notify();
}
/*
setCount 改造成生产包子
count++
*/
public synchronized void setCount() {
//1.判断flag是否为true,如果是true,证明有包子,生产线程等待
if (this.flag == true) {
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//2.如果flag为false,证明没有包子,开始生产
count++;
System.out.println("生产了...第" + count + "个包子");
//3.改变flag状态,为true,证明生产完了,有包子了
this.flag = true;
//4.唤醒消费线程
this.notify();
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
public class Product implements Runnable{
private BaoZiPu baoZiPu;
public Product(BaoZiPu baoZiPu) {
this.baoZiPu = baoZiPu;
}
@Override
public void run() {
while(true){
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
baoZiPu.setCount();
}
}
}
public class Consumer implements Runnable{
private BaoZiPu baoZiPu;
public Consumer(BaoZiPu baoZiPu) {
this.baoZiPu = baoZiPu;
}
@Override
public void run() {
while(true){
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
baoZiPu.getCount();
}
}
}
public class Test01 {
public static void main(String[] args) {
BaoZiPu baoZiPu = new BaoZiPu();
Product product = new Product(baoZiPu);
Consumer consumer = new Consumer(baoZiPu);
Thread t1 = new Thread(product);
Thread t2 = new Thread(consumer);
t1.start();
t2.start();
}
}
4. 多等待多唤醒
1. 解决多生产多消费问题
if 改为 while, 将 notify 改为 notifyAll
public class Test01 {
public static void main(String[] args) {
BaoZiPu baoZiPu = new BaoZiPu();
Product product = new Product(baoZiPu);
Consumer consumer = new Consumer(baoZiPu);
new Thread(product).start();
new Thread(product).start();
new Thread(product).start();
new Thread(consumer).start();
new Thread(consumer).start();
new Thread(consumer).start();
}
}
/*
count和flag可以定义成包装类
但是要记得给count和flag手动赋值
不然对于本案例来说,容易出现空指针异常
*/
public class BaoZiPu {
//代表包子的count
private int count;
//代表是否有包子的flag
private boolean flag;
public BaoZiPu() {
}
public BaoZiPu(int count, boolean flag) {
this.count = count;
this.flag = flag;
}
/*
getCount 改造成消费包子方法
直接输出count
*/
public synchronized void getCount() {
//1.判断flag是否为false,如果是false,证明没有包子,消费线程等待
while (this.flag == false) {
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//2.如果flag为true,证明有包子,开始消费
System.out.println("消费了..............第" + count + "个包子");
//3.改变flag状态,为false,证明消费完了,没 有包子了
this.flag = false;
//4.唤醒所有等待线程
this.notifyAll();
}
/*
setCount 改造成生产包子
count++
*/
public synchronized void setCount() {
//1.判断flag是否为true,如果是true,证明有包子,生产线程等待
while (this.flag == true) {
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//2.如果flag为false,证明没有包子,开始生产
count++;
System.out.println("生产了...第" + count + "个包子");
//3.改变flag状态,为true,证明生产完了,有包子了
this.flag = true;
//4.唤醒所有等待线程
this.notifyAll();
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
public class Product implements Runnable{
private BaoZiPu baoZiPu;
public Product(BaoZiPu baoZiPu) {
this.baoZiPu = baoZiPu;
}
@Override
public void run() {
while(true){
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
baoZiPu.setCount();
}
}
}
public class Consumer implements Runnable{
private BaoZiPu baoZiPu;
public Consumer(BaoZiPu baoZiPu) {
this.baoZiPu = baoZiPu;
}
@Override
public void run() {
while(true){
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
baoZiPu.getCount();
}
}
}