海量数据处理:从并发编程到分布式系统

本系列文章主要围绕高并发这一话题展开,分享笔者在并发处理上的学习思路以及踩过的坑。具体思路大体分为三部分:

d47e62d2b349aca45e42305ed6714efbe5ed61d9Java多线程编程;
d47e62d2b349aca45e42305ed6714efbe5ed61d9高并发的解决思路;
d47e62d2b349aca45e42305ed6714efbe5ed61d9分布式架构中Redis、Zookeeper分布式锁的应用。

本文将重点讲解第一部分——Java多线程编程。

一、Java内存模型与线程

并发编程主要讨论以下几点:

d47e62d2b349aca45e42305ed6714efbe5ed61d9多个线程操作相同资源
d47e62d2b349aca45e42305ed6714efbe5ed61d9保证线程安全
d47e62d2b349aca45e42305ed6714efbe5ed61d9合理使用资源

通常我们可以将物理计算机中出现的并发问题类比到JVM中的并发。

物理计算机处理器、高速缓存、主内存间交互关系如图:

d9905aab152284e60203e6787741273063c1705b

处理器和内存的运行速度存在几个数量级别的差距,因此为解决此矛盾引入了“高速缓存”这一概念。当多个处理器的运行任务都涉及到同一块主内存区域时,就可能导致各自缓存数据的不一致问题。为解决一致性问题,需要各个处理器访问缓存时都遵循一些协议,在读写时要根据协议来进行操作。(MSI、MESI、MOSI、Synapse、Firefly及Dragon Protocol等)

处理器为提高性能,会对输入代码乱序执行(Out-Of-Order Execution) 优化。

类比Java内存模型,线程、主内存、工作内存交互关系如图:

6c3b06dc5c6462bd8231daf1520ba3477509e036

JMM定义了程序中各个变量访问规则,即在虚拟机中将内存取出和存储的底层细节。

ee18f71083dd84f0c43a2c5cbd543e0afb712d56

线程A如果要跟线程B要通信的话,必须经历以下两个步骤:

d47e62d2b349aca45e42305ed6714efbe5ed61d9线程A把本地内存A中更新过的共享变量的值刷新到主内存中;
d47e62d2b349aca45e42305ed6714efbe5ed61d9线程B去主内存中读取A更新过的共享变量的值。

线程的工作内存中保存了该线程使用到变量的主内存副本拷贝(也可理解为此线程的私有拷贝),线程对变量的操作(读取、赋值等)都在工作内存中进行,而不能直接读写主内存中变量。不同线程之间的通信也需要通过主内存来完成。主内存对应Java堆中对象实例数据部分,而工作内存则对应虚拟机栈中部分区域。

原文链接

阅读更多
上一篇使用zookeeper实现分布式锁
下一篇为什么说 Java 程序员到了必须掌握 Spring Boot 的时候?
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭