一、生产者消费者模式(只有两个线程一个是生产者线程一个是消费者线程)
重点!!!!!!!看这篇博客的时候首先要描述一下wait()方法的等待机制,当当先线程被wait之后会释放锁,当这个线程被唤醒的时候会继续从wait方法后面的代码继续执行。这个点也是这篇文章的点睛之笔,重中之重。也是为什么不用if用while的原因。
小声bb:我也是翻阅好多文章才知道线程阻塞,被唤醒之后竟然会接着执行线程wait方法后面的代码。我原来竟然一直傻逼的认为这个线程被阻塞之后会重新执行。菜鸟就是我我就是彩笔。
首先看一下只有一个生产者和线程一个消费者线程的情况,这个时候使用if
(多个生产者和消费者线程的时候一定要使用while
,下面会接着描述)不会出现数据错误,因为只有两个线程调用this.notifyAll()
的时候只会唤醒所有的线程,但是这个时候只有一个等待线程。代码如下:
package com.aa.生产者消费者模式;
public class A {
public static void main(String[] args) {
Data data = new Data();
//生产者线程A1
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"生产者A1").start();
//消费者线程B1
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"消费者B1").start();
}
}
//这是是共享区域data,里面只有一个属性num
class Data{
private int num=0;
//生产者对 num++
public synchronized void increment() throws InterruptedException {
//我是故意用if的,在这里不会出错,因为只有两个线程,被唤醒的只能是消费者线程,对num--
if(num!=0){
this.wait(); //此时线程阻塞,让线程被唤醒之后会重新继续执行后续代码,这也是为什么不用if用while的原因
}
num++;
System.out.println(Thread.currentThread().getName()+"==="+num);
//唤醒其他线程
this.notifyAll();
}
//消费者对 num--
public synchronized void decrement() throws InterruptedException {
//我是故意用if的,在这里不会出错,因为只有两个线程,被唤醒的只能是生产者线程
if (num==0){
this.wait();//此时线程阻塞,让线程被唤醒之后会重新继续执行后续代码,这也是为什么不用if用while的原因
}
num--;
System.out.println(Thread.currentThread().getName()+"==="+num);
//唤醒其他等待的线程
this.notifyAll();
}
}
这个是程序正常运行的结果:
二、然后给大家演示一下开始四个线程,两个消费者线程两个生产者线程
此时有生产者A1,生产者A2,消费者B1,消费者B2
package com.aa.生产者消费者模式;
public class A {
public static void main(String[] args) {
Data data = new Data();
//生产者线程A1
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"生产者A1").start();
//消费者线程B1
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"消费者B1").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"生产者A2").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"消费者B2").start();
}
}
//这是是共享区域data,里面只有一个属性num
class Data{
private int num=0;
//生产者对 num++
public synchronized void increment() throws InterruptedException {
if(num!=0){
this.wait(); //此时线程阻塞,让线程被唤醒之后会重新继续执行后续代码,这也是为什么不用if用while的原因
}
num++;
System.out.println(Thread.currentThread().getName()+"==="+num);
//唤醒其他线程
this.notifyAll();
}
//消费者对 num--
public synchronized void decrement() throws InterruptedException {
if (num==0){
this.wait();//此时线程阻塞,让线程被唤醒之后会重新继续执行后续代码,这也是为什么不用if用while的原因
}
num--;
System.out.println(Thread.currentThread().getName()+"==="+num);
//唤醒其他等待的线程
this.notifyAll();
}
}
然后给大家看一下运行效果:
前面运行还算正常,后面就不正常了。而且会出现死循环。程序一直运行。主要就是因为使用了if语句
当线程阻塞后,被挂起,当其他线程使用notifyAll()
之后,假如这个线程被执行了,这个被挂起的线程会接着执行wait()
方法后面的代码,对num++
或者num--
,但是如果使用while替代if之后他会一直判断当前条件满不满足不满足接着被wait()
直至不满足while
的判断语句时之后才会继续执行,而if是直接执行不会再次进行判断。
三、正确的生产者消费者模式
正确的生产者消费者代码如下:
package com.aa.生产者消费者模式;
public class A {
public static void main(String[] args) {
Data data = new Data();
//生产者线程A1
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"生产者A1").start();
//消费者线程B1
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"消费者B1").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"生产者A2").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"消费者B2").start();
}
}
//这是是共享区域data,里面只有一个属性num
class Data{
private int num=0;
//生产者对 num++
public synchronized void increment() throws InterruptedException {
while(num!=0){
this.wait(); //此时线程阻塞,让线程被唤醒之后会重新继续执行后续代码,这也是为什么不用if用while的原因
}
num++;
System.out.println(Thread.currentThread().getName()+"==="+num);
//唤醒其他线程
this.notifyAll();
}
//消费者对 num--
public synchronized void decrement() throws InterruptedException {
while (num==0){
this.wait();//此时线程阻塞,让线程被唤醒之后会重新继续执行后续代码,这也是为什么不用if用while的原因
}
num--;
System.out.println(Thread.currentThread().getName()+"==="+num);
//唤醒其他等待的线程
this.notifyAll();
}
}
程序运行之后的效果如下:
我刚开始也是不理解while和if在生产者和消费者之间的区别,我也是在经历校招准备面试某公司很长时间失败之后,才偶然发现的。于是奋笔疾书给大家分享一下,希望能够帮助大家顺利找到心仪的公司,小声bb菜鸡找工作真难,一次一次降低自己的标准,唉!愿:心所想,有所成,加油各位!!!冲!!!