MST

星途 面试题库

面试题:Kotlin协程Channel通信原理之缓冲区管理

假设我们有一个Channel,缓冲区大小为5。解释缓冲区满时生产者和缓冲区空时消费者的行为。如何通过代码实现一个策略,当缓冲区满时生产者暂停生产,直到缓冲区有空间;当缓冲区空时消费者暂停消费,直到缓冲区有数据。
34.6万 热度难度
编程语言Kotlin

知识考点

AI 面试

面试题答案

一键面试
  1. 缓冲区满时生产者行为
    • 当缓冲区满时,生产者尝试向已满的缓冲区发送数据,会导致生产者阻塞,即生产者线程会暂停执行,等待缓冲区有可用空间。
  2. 缓冲区空时消费者行为
    • 当缓冲区空时,消费者尝试从空的缓冲区接收数据,会导致消费者阻塞,即消费者线程会暂停执行,等待缓冲区有数据。
  3. 代码实现策略(以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代码中:

  • BlockingQueueput方法在队列满时会阻塞生产者线程,直到队列有空间。
  • take方法在队列空时会阻塞消费者线程,直到队列有数据。