面试题答案
一键面试- 缓冲区满时生产者行为:
- 当缓冲区满时,生产者尝试向已满的缓冲区发送数据,会导致生产者阻塞,即生产者线程会暂停执行,等待缓冲区有可用空间。
- 缓冲区空时消费者行为:
- 当缓冲区空时,消费者尝试从空的缓冲区接收数据,会导致消费者阻塞,即消费者线程会暂停执行,等待缓冲区有数据。
- 代码实现策略(以Go语言为例):
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int, 5)
// 生产者
go func() {
for i := 0; i < 10; i++ {
ch <- i
fmt.Printf("Produced: %d\n", i)
}
close(ch)
}()
// 消费者
go func() {
for val := range ch {
fmt.Printf("Consumed: %d\n", val)
time.Sleep(100 * time.Millisecond)
}
}()
time.Sleep(2 * time.Second)
}
在上述代码中:
- 生产者向
ch
通道发送数据,当缓冲区满时,ch <- i
这一行代码会阻塞,直到缓冲区有空间。 - 消费者从
ch
通道接收数据,当缓冲区空时,for val := range ch
会阻塞,直到缓冲区有数据。for val := range ch
会自动处理通道关闭的情况,当通道关闭且缓冲区数据都被消费完后,循环结束。
如果是Java,可以使用BlockingQueue
来实现类似功能:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
class Producer implements Runnable {
private final BlockingQueue<Integer> queue;
public Producer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
queue.put(i);
System.out.println("Produced: " + i);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
class Consumer implements Runnable {
private final BlockingQueue<Integer> queue;
public Consumer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
while (true) {
try {
Integer val = queue.take();
System.out.println("Consumed: " + val);
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
}
public class Main {
public static void main(String[] args) {
BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(5);
Thread producerThread = new Thread(new Producer(queue));
Thread consumerThread = new Thread(new Consumer(queue));
producerThread.start();
consumerThread.start();
try {
producerThread.join();
consumerThread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
在Java代码中:
BlockingQueue
的put
方法在队列满时会阻塞生产者线程,直到队列有空间。take
方法在队列空时会阻塞消费者线程,直到队列有数据。