目录
前言
在现代软件开发中,多线程编程能力已经成为程序员必须掌握的一项核心技能。随着计算机硬件的不断升级,单核CPU早已无法满足复杂应用的性能需求,多核并行运算已成为主流。而多线程正是实现资源最大化利用、任务高效并行执行的基础手段。
而本博客是笔者多线程编程的第四篇博客!
前三篇URL在此:
如何简单的去使用jconsloe 查看线程 (多线程编程篇1)_java jconsloe-优快云博客
浅谈Thread类及常见方法与线程的状态(多线程编程篇2)_thread.join() 和thread.get()-优快云博客
多线程编程的简单案例——单例模式[多线程编程篇(3)]-优快云博客
笔者将继续介绍和分享学习多线程编程时遇见过的简单案例, 希望读者们通过这些简单案例能加深对于多线程编程的理解
在本篇博客中,笔者将会分享两个知识点:
1.阻塞式队列
2.生产者消费者模型
为什么分享呢
其实原因很简单:根据资料显示,阻塞式队列,是多线程编程里非常经典、非常实用的模型。在实际开发中,无论是任务调度、生产者消费者,还是定时触发某些功能,模型几乎无处不在。
可以说:理解它,就等于掌握了并发编程的一块基础地基。
那么,让我们开始介绍阻塞队列吧!!!!
博客中出现的参考图都是笔者手画的,代码示例也是笔者手敲的!影响虽小,但请勿抄袭
阻塞队列
首先我们要明白,阻塞队列作为一种数据结构,阻塞只是定语,它终究是一种队列,作为队列,它也同样遵守"先进先出"的规则
但它与一般的队列又有不同,它拥有以下的特征:
1.当队列满的时候 , 继续入队列就会阻塞 , 直到有其他线程从队列中取走元素 .
2.当队列空的时候 , 继续出队列也会阻塞 , 直到有其他线程往队列中插入元素 .
你可以理解为一个传送带:
-
一边的工人(线程)往上传送包裹 -> put()
-
另一边的工人(线程)从传送带上取包裹 -> take()
如果传送带满了,送货的工人只能在原地等着;如果传送带空了,取货的工人也得站着干等。
阻塞队列相比普通队列的优势
结合网上各类资料说明,我大致总结出了那么三点
1.天然线程安全
普通队列在多线程场景下,容易出现数据错乱、并发冲突,需要我们手动加锁,编写复杂的同步逻辑。而阻塞队列内部已经实现了线程安全机制,不需要我们操心锁的问题,简化开发,避免Bug。
举个例子:下面的代码演示了在多线程环境下使用普通队列,可能出现的问题
import java.util.LinkedList;
import java.util.Queue;
public class NormalQueueTest {
static Queue<Integer> queue = new LinkedList<>();
public static void main(String[] args) throws InterruptedException {
Thread producer = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
queue.add(i); // 非线程安全,可能抛异常
}
});
Thread consumer = new Thread(() -> {
int count = 0;
while (count < 10000) {
Integer val = queue.poll(); // 可能返回 null,导致数据丢失
if (val != null) {
count++;
}
}
});
producer.start();
consumer.start();
producer.join();
consumer.join();
//检查队列是否为空、数量是否一致
System.out.println("剩余元素数量:" + queue.size());
System.out.println("主线程走到这里了?");
}
}
笔者使用两个线程,一个负责生产数据 producer,另一个负责消费数据 consumer
生产线程尝试向队列中添加 10,000 个整数;
消费线程尝试从队列中取出 10,000 个元素;
期望结果: 所有数据被完整消费,最终队列应为空,输出结果应为:
多线程编程:阻塞队列介绍与简单实现

最低0.47元/天 解锁文章





