传统模式下的生产者消费者
1、synchronized控制的
class Data{
int number = 0;
AtomicInteger atomicInteger = new AtomicInteger(0);
public void increment(){
synchronized (this){
// 不等于0进行,等待消费者消费
while (number != 0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 生产
number++;
System.out.println(Thread.currentThread().getName()+" 生产了一个产品: " +number);
// 通知消费者消费
this.notify();
}
}
public void decrement(){
synchronized (this){
// 等待生产者生产
while (number == 0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 消费
number--;
System.out.println(Thread.currentThread().getName()+" 消费了一个产品: " +number);
// 通知生产者生产
this.notify();
}
}
}
public static void main(String[] args) {
// 任务: 生产一个消费一个
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 5; i++) {
data.increment();
}
},"producer").start();
new Thread(()->{
for (int i = 0; i < 5; i++) {
data.decrement();
}
},"consumer").start();
}
2、lock(ReentrantLock)
class Data{
int number = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void increment(){
lock.lock();
try {
// 不等于0进行,等待消费者消费
while (number != 0){
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 生产
number++;
System.out.println(Thread.currentThread().getName()+" 生产了一个产品: " +number);
// 通知消费者消费
condition.signal();
}finally {
lock.unlock();
}
}
public void decrement(){
lock.lock();
try {
// 等待生产者生产
while (number == 0){
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 消费
number--;
System.out.println(Thread.currentThread().getName()+" 消费了一个产品: " +number);
// 通知生产者生产
condition.signal();
}finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
// 任务: 生产一个消费一个
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 5; i++) {
data.increment();
}
},"producer").start();
new Thread(()->{
for (int i = 0; i < 5; i++) {
data.decrement();
}
},"consumer").start();
}
两者运行结果:
虚假唤醒问题
存在多个线程并发争抢一个资源。以生产者消费者为例:
我们任务要求,只能生产一个产品消费一个产品。两个生产者生产,两个消费者消费。
当生产者生产完一个产品时,要唤醒等待的线程(notify是随机唤醒)。注意此时有两个消费者线程,一个生产者线程等待。如果cpu的调度权被等待的生产者获取到了,此时生产者在 wait()方法处 会直接往下执行,实际上就生产了两个产品。同理消费者也可能同时消费两个产品
根源在于:换性的线程是直接往下执行的并没有判断是否满足对应条件
产生虚假唤醒的源码
class Data{
int number = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void increment(){
lock.lock();
try {
// 不等于0进行,等待消费者消费
if (number != 0){
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 生产
number++;
System.out.println(Thread.currentThread().getName()+" 生产了一个产品: " +number);
// 通知消费者消费
condition.signal();
}finally {
lock.unlock();
}
}
public void decrement(){
lock.lock();
try {
// 等待生产者生产
if (number == 0){
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 消费
number--;
System.out.println(Thread.currentThread().getName()+" 消费了一个产品: " +number);
// 通知生产者生产
condition.signal();
}finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
// 任务: 生产一个消费一个
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 5; i++) {
data.increment();
}
},"producer").start();
new Thread(()->{
for (int i = 0; i < 5; i++) {
data.decrement();
}
},"consumer").start();
new Thread(()->{
for (int i = 0; i < 5; i++) {
data.increment();
}
},"producer1").start();
new Thread(()->{
for (int i = 0; i < 5; i++) {
data.decrement();
}
},"consumer2").start();
}
可能的结果
解决:
if该while即可,唤醒的同时,进行再次判断