面试题答案
一键面试资源管理
- 连接资源:使用连接池管理Socket连接,对连接的创建、获取、释放进行统一管理。例如,初始化一定数量的连接对象放入池中,线程需要时从池中获取,使用完毕后归还。这样可以避免频繁创建和销毁连接带来的开销,同时保证连接资源的合理分配。
- 内存资源:对于接收和发送的数据缓冲区,采用内存池技术。预先分配一定大小的内存块,线程使用时直接从内存池获取,使用完归还。避免频繁的内存分配和释放导致的内存碎片问题,提高内存使用效率。
同步机制
- 锁机制:
- 互斥锁(Mutex):用于保护共享资源,如连接池、内存池等。在访问这些共享资源前加锁,访问结束后解锁。例如,当一个线程要从连接池中获取连接时,先获取互斥锁,获取连接后再释放锁。
- 读写锁(Read - Write Lock):对于读多写少的场景,如读取配置信息等共享数据,使用读写锁。多个线程可以同时获取读锁进行读取操作,但写操作需要获取写锁,此时其他线程不能获取读锁或写锁,以保证数据一致性。
- 信号量(Semaphore):控制同时访问共享资源的线程数量。比如,限制连接池同时被获取的连接数量,通过信号量来实现。当信号量的值大于0时,线程可以获取信号量(信号量值减1)并访问共享资源,使用完毕后释放信号量(信号量值加1)。
数据结构选择
- 队列:用于存储待处理的网络消息。采用线程安全的队列,如生产者 - 消费者模型中的阻塞队列。生产者线程(如接收数据的线程)将接收到的消息放入队列,消费者线程(如处理业务逻辑的线程)从队列中取出消息进行处理。这样可以避免不同线程同时访问队列导致的数据竞争。
- 哈希表:在管理连接等信息时,使用线程安全的哈希表。例如,通过连接的唯一标识作为键,连接对象作为值存储在哈希表中。在多线程环境下,对哈希表的插入、删除、查找操作需要进行同步保护。
处理不同线程对共享资源的访问,避免死锁和数据竞争
- 死锁避免:
- 资源分配图算法:可以采用死锁检测算法,如资源分配图算法。定期检测系统中的资源分配情况,当检测到死锁时,采取措施打破死锁,如选择一个牺牲者线程,释放其占用的资源。
- 锁顺序:规定所有线程获取锁的顺序。例如,在获取多个锁时,按照锁的唯一标识从小到大的顺序获取锁,这样可以避免由于获取锁顺序不一致导致的死锁。
- 数据竞争避免:
- 原子操作:对于简单的共享变量,如计数器等,使用原子操作。例如,在统计已处理的消息数量时,使用原子变量的自增操作,而不是普通的变量自增,原子操作由硬件或操作系统保证其操作的原子性,不会出现数据竞争。
- 线程本地存储(TLS):对于一些不需要共享的数据,如每个线程的临时计算结果等,使用线程本地存储。每个线程有自己独立的存储空间,避免了线程间的数据竞争。