并发编程的两大核心问题:
- 互斥:同一时刻只允许一个线程访问资源;
- 同步:线程间如何通讯、协作; 管程:管理共享变量和共享变量的操作过程;在Java中,就是管理类的成员变量和成员方法,让这个类是线程安全的;
在管程模型里,共享变量和对共享变量的操作是被封装起来的,图中最外层的框就代表封装的意思。框的上面只有一个入口,并且在入口旁边还有一个入口等待队列。当多个线程同时试图进入管程内部时,只允许一个线程进入,其他线程则在入口等待队列中等待。这个过程类似就医流程的分诊,只允许一个患者就诊,其他患者都在门口等待。
package com.imooc.interview.basic;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class BoundedBuffer {
private final Queue<Integer> queue;
private final int capacity;
private final Lock lock;
private final Condition notFull;
private final Condition notEmpty;
public BoundedBuffer(int capacity) {
this.queue = new LinkedList<>();
this.capacity = capacity;
this.lock = new ReentrantLock();
this.notFull = lock.newCondition();
this.notEmpty = lock.newCondition();
}
public void produce(int item) throws InterruptedException {
lock.lock();
try {
while (queue.size() == capacity) {
notFull.await(); // 等待缓冲区未满
}
queue.offer(item);
notEmpty.signal(); // 通知消费者缓冲区不为空
} finally {
lock.unlock();
}
}
public int consume() throws InterruptedException {
lock.lock();
try {
while (queue.isEmpty()) {
notEmpty.await(); // 等待缓冲区不为空
}
int item = queue.poll();
notFull.signal(); // 通知生产者缓冲区未满
return item;
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
BoundedBuffer buffer = new BoundedBuffer(10);
Thread producer = new Thread(() -> {
try {
for (int i = 0; i < 20; i++) {
buffer.produce(i);
System.out.println("Produced: " + i);
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread consumer = new Thread(() -> {
try {
for (int i = 0; i < 20; i++) {
int item = buffer.consume();
System.out.println("Consumed: " + item);
Thread.sleep(150);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
producer.start();
consumer.start();
}
}