当前位置: 首页 > news >正文 傻瓜做网站泰州网站设计哪家好 news 2025/10/25 22:05:02 傻瓜做网站,泰州网站设计哪家好,东莞网站建设公司口碑排名,服装公司网站建设方案大家好#xff0c;我是栗筝i#xff0c;这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 022 篇文章#xff0c;在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验#xff0c;并希望进… 大家好我是栗筝i这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 022 篇文章在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验并希望进一步完善自己对整个 Java 技术体系来充实自己的技术栈的同学。与此同时本专栏的所有文章也都会准备充足的代码示例和完善的知识点梳理因此也十分适合零基础的小白和要准备工作面试的同学学习。当然我也会在必要的时候进行相关技术深度的技术解读相信即使是拥有多年 Java 开发经验的从业者和大佬们也会有所收获并找到乐趣。 – 在当今多核处理器和高并发应用日益普及的时代理解并掌握 Java 并发编程变得尤为重要。Java 内存模型Java Memory Model, JMM作为并发编程的基石扮演着至关重要的角色。JMM 定义了多线程环境下变量的访问规则确保程序在不同平台和处理器上能够一致且正确地运行。 本文将深入探讨 Java 内存模型中的核心概念包括处理器优化、指令重排序与内存屏障。我们将揭示这些技术如何影响 Java 程序的执行顺序和数据可见性以及开发者如何利用 JMM 的规则来编写高效、安全的并发程序。通过对这些概念的理解您将能够更好地应对并发编程中的挑战编写出性能优越且健壮的 Java 应用程序。 文章目录 1、计算机的硬件内存架构1.1、CPU 高速缓存1.2、缓存一致性问题1.3、处理器优化和指令重排序 2、Java 并发编程中存在的问题3、Java 内存模型3.1、Java 内存划分3.2、Java 内存交互3.3、Java 线程通信 4、处理器重排序与内存屏障指令4.1、顺序性与可见性问题4.2、As-if-serial 原则4.3、Java 内存屏障的使用4.4、Java 内存屏障的实现 5、Java 内存模型的相关概念5.1、happens-before 规则5.2、Java 内存模型三大特征5.2.1、原子性5.2.2、可见性5.2.3、有序性 1、计算机的硬件内存架构 在介绍 Java 内存模型之前我们很有必要的了解的一个知识点就是计算机的硬件内存架构。‘ 1.1、CPU 高速缓存 对计算机知识有最基础了解的同学都会知道大多数计算机都是由四大要素组成即 CPU、内存、I/O 设备和总线。而对于存储硬件来说速度快的成本高、容量小速度慢的成本低、容量大。 其中 CPU 寄存器的速度和内存的速度差异可以非常大具体倍数取决于多种因素包括 CPU 的型号、内存的类型以及系统的整体架构等。但一般来说CPU 寄存器访问速度远快于内存访问速度这个速度差异可以达到几个数量级几百倍甚至上千倍。所以在传统计算机内存架构中会引入高速缓存来作为主存和处理器之间的缓冲CPU 将常用的数据放在高速缓存中运算结束后 CPU 再将运算结果同步到主存中。 处理器 ( C P U ) − 高速缓存 ( C P U C a c h e M e n o r y ) − 主内存 ( M a i n M e m o r y ) 处理器(CPU) - 高速缓存(CPU Cache Menory) - 主内存(Main Memory) 处理器(CPU)−高速缓存(CPUCacheMenory)−主内存(MainMemory) 高速缓存如今的实现是多级缓存的形式不同级别的缓存具有不同的容量、速度和访问延迟。一般来说缓存层次越接近 CPU其速度越快但容量越小反之层次越远离CPU其速度越慢但容量越大。 一级缓存L1 Cache最接近 CPU 的缓存通常分为数据缓存D-Cache和指令缓存I-Cache。L1 缓存的容量较小但访问速度极快几乎与 CPU 同频运作。每个 CPU 核心通常都有自己的L1缓存。二级缓存L2 Cache位于 L1 缓存和主内存之间容量比 L1 缓存大但速度稍慢。在早期的 CPU 设计中L2 缓存可能独立于 CPU 核心存在但现代 CPU 通常将 L2 缓存集成到核心内部。每个CPU核心可能有一个独立的L2缓存或者多个核心共享一个L2缓存。三级缓存L3 Cache位于 L2 缓存和主内存之间是 CPU 缓存中最大的一级。L3 缓存的容量远大于 L1 和 L2 缓存但访问速度相对较慢。在多核 CPU 中L3 缓存通常由所有核心共享以减少核心间访问共享数据的延迟。 使用高速缓存解决了 CPU 和主存速率不匹配的问题但同时又引入另外一个新问题缓存一致性问题。 1.2、缓存一致性问题 缓存一致性问题是在多处理器或多核处理器系统中面临的一个重要挑战。在多处理器系统中每个处理器都可能拥有自己的高速缓存用于加速对常用数据的访问。然而它们是共享同一主内存Main Memory当多个处理器同时访问和修改同一数据块时就可能出现数据不一致的情况。如果每个处理器的高速缓存中都存储了该数据块的副本并且这些副本之间没有得到适当的同步那么它们之间就可能产生差异。 因此需要每个 CPU 访问缓存时遵循一定的协议这类定义了高速缓存行Cache Line的状态和状态之间的转换规则以及处理器之间如何通过消息传递来协调对这些缓存行的访问和修改高速缓存在读写数据时根据协议进行操作共同来维护缓存的一致性。这类协议有 MSI、MESI、MOSI、和 Dragon Protocol 等 多个处理器 ( C P U ) − 多个高速缓存 ( C P U C a c h e M e n o r y ) − 缓存一致性协议 − 主内存 ( M a i n M e m o r y ) 多个处理器(CPU) - 多个高速缓存(CPU Cache Menory)- 缓存一致性协议- 主内存(Main Memory) 多个处理器(CPU)−多个高速缓存(CPUCacheMenory)−缓存一致性协议−主内存(MainMemory) 以 MESI 协议为例它定义了四种缓存状态 Modified修改缓存行中的数据已被本地处理器修改并且与内存中的数据不同步且其他处理器的缓存中不存在该缓存行的最新副本。此时该缓存行是最新的Exclusive独占缓存行中的数据没有被修改且只有本地处理器拥有该数据的缓存副本。该缓存行与内存中的数据保持一致Shared共享缓存行中的数据没有被修改且可能被其他处理器缓存。此时多个处理器的缓存中存在同一份数据的副本并且这些副本与内存中的数据保持一致。Invalid无效缓存行中的数据是无效的即该缓存行中的数据不再代表内存中的最新数据。处理器在访问无效缓存行时需要从内存中重新加载数据。 缓存一致性协议通过定义状态之间的转换规则和处理器之间的消息传递机制来保持缓存一致性。当处理器对缓存行进行操作时如读取、写入、无效化等它会根据当前状态和操作类型来更新缓存行的状态并向其他处理器发送相应的消息。 当一个处理器想要读取一个共享状态的缓存行时它可以直接从自己的缓存中读取数据无需与内存或其他处理器交互当一个处理器想要修改一个共享状态的缓存行时它必须首先将缓存行的状态转换为修改状态并向其他处理器发送 Invalidate 消息来使它们的缓存行无效化。只有在收到所有相关处理器的 Invalidate Acknowledge 消息后该处理器才能开始修改数据当一个处理器执行写回操作时如缓存行被替换出缓存时如果缓存行处于修改状态它需要将修改后的数据写回内存并可能向其他处理器发送相应的消息来更新它们的缓存状态。 1.3、处理器优化和指令重排序 除了在 CPU 和主内存之间增加高速缓存还有什么办法可以进一步提升 CPU 的执行效率呢答案是处理器优化和指令重排序。 处理器优化使处理器内部的运算单元能够最大化被充分利用处理器会对输入代码进行乱序执行处理。其工作原理 指令分派Instruction Dispatch: 处理器从指令队列中取出多条指令并分派到多个执行单元。每个执行单元可以独立处理不同的指令指令窗口Instruction Window: 处理器维护一个指令窗口其中包含了即将执行的指令。指令可以在这个窗口中进行重新排序以便尽可能地避免资源冲突数据依赖性分析Data Dependency Analysis: 处理器分析指令之间的依赖关系。如果某条指令的执行依赖于另一条指令的结果那么这条指令必须等到依赖的指令执行完毕后才能执行执行单元调度Execution Unit Scheduling: 处理器根据指令的资源需求和依赖关系动态地调度指令到可用的执行单元上。只要某条指令所需的资源和数据都准备好了就可以立即执行而不必等待前面的指令全部执行完毕结果重排序Reorder Buffer: 处理器使用重排序缓冲区来保存指令的执行结果。虽然指令是乱序执行的但它们的结果会按照程序代码的顺序提交给寄存器或存储器以确保程序的最终结果正确。 2、Java 并发编程中存在的问题 上面讲了计算机的硬件内存架构相关的相关知识可能会有一些同学开始好奇了绕了这么一大圈这些和 Java 内存模型有什么关系么 当时是有关系的Java 并发编程领域最常提到的三个问题“可见性问题”、“原子性问题”、“有序性问题”其实就是上面提到的 “缓存一致性”、“处理器优化” 和 “指令重排序” 造成的。 缓存一致性问题其实就是可见性问题处理器优化可能会造成原子性问题指令重排序会造成有序性问题。这便是其中的关联 出了问题定然是需要解决的那有什么办法呢一个简单粗暴的办法就是直接干掉缓存让 CPU 直接与主内存交互就解决了可见性问题禁止处理器优化和指令重排序就解决了原子性和有序性问题但这样相当于整个否定了现代计算机的硬件内存架构显然不可取的。 所以技术前辈们想到了在物理机器上定义出一套内存模型 规范内存的读写操作。内存模型解决并发问题主要采用两种方式限制处理器优化和使用内存屏障。 3、Java 内存模型 Java 内存模型JMMJava Memory Model用于屏蔽掉各种硬件和操作系统的内存访问差异以实现让 Java 程序在各种平台下都能达到一致的并发效果JMM 规范了Java 虚拟机与计算机内存是如何协同工作的规定了一个线程如何和何时可以看到由其他线程修改过后的共享变量的值以及在必须时如何同步的访问共享变量。 3.1、Java 内存划分 在 JMM 中规定了内存主要划分为主内存和工作内存两种。此处的主内存和工作内存跟 JVM 内存划分堆、栈、方法区是在不同的层次上进行的。如果非要对应起来主内存对应的是 Java 堆中的对象实例部分工作内存对应的是栈中的部分区域。从更底层的来说主内存对应的是硬件的物理内存工作内存对应的是寄存器和高速缓存。 同样的在 JMM 定义的访问规则中所有变量都存储在主内存线程均有自己的工作内存。工作内存中保存被该线程使用的变量的主内存副本线程对变量的所有操作都必须在工作空间进行不能直接读写主内存数据。操作完成后线程的工作内存通过缓存一致性协议将操作完的数据刷回主存。 3.2、Java 内存交互 线程的工作内存中保存了该线程使用到的变量到主内存副本拷贝线程对变量的所有操作读取、赋值都必须在工作内存中进行而不能直接读写主内存中的变量。不同线程之间无法直接访问对方工作内存中的变量线程间变量值的传递均需要在主内存来完成。 但是这样就会出现一个问题当一个线程修改了自己工作内存中变量对其他线程是不可见的会导致线程不安全的问题。因此 JMM 制定了一套标准来保证开发者在编写多线程程序的时候能够控制什么时候内存会被同步给其他线程。 JMM 中规定了 8 种线程、主内存和工作内存的交互关系每种操作都有自己作用的的区域具体操作如下 lock锁定作用于主内存的变量把一个变量标识为线程独占状态unlock解锁作用于主内存的变量它把一个处于锁定状态的变量释放出来释放后的变量才可以被其他线程锁定read 读取作用于主内存变量它把一个变量的值从主内存传输到线程的工作内存中以便随后的 load 动作使用load载入作用于工作内存的变量它把 read 操作从主存中变量放入工作内存中use使用作用于工作内存中的变量它把工作内存中的变量传输给执行引擎每当虚拟机遇到一个需要使用到变量的值就会使用到这个指令assign赋值作用于工作内存中的变量它把一个从执行引擎中接受到的值放入工作内存的变量副本中store存储作用于主内存中的变量它把一个从工作内存中一个变量的值传送到主内存中以便后续的 write 使用write写入作用于主内存中的变量它把 store 操作从工作内存中得到的变量的值放入主内存的变量中。 3.3、Java 线程通信 JMM 中的 8 种操作规定了线程对主内存的操作过程隐式的规定线程之间要通信必须通过主内存JMM 的线程通信如下图所示 从上图来看线程 A 与线程 B 之间如要通信的话必须要经历下面 2 个步骤 首先线程 A 把本地内存 A 中更新过的共享变量刷新到主内存中去然后线程 B 到主内存中去读取线程 A 之前已更新过的共享变量。 要把一个变量从主内存中复制到工作内存就需要按顺序地执行 read 和 load 操作如果把变量从工作内存中同步回主内存中就要按顺序地执行 store 和 write 操作。 Java 内存模型只要求上述两个操作必须按顺序执行而没有保证必须是连续执行。也就是 read 和 load 之间store 和 write 之间是可以插入其他指令的。 Java 内存模型还规定了在执行上述八种基本操作时必须满足如下规则 不允许 read 和 load、store 和 write 操作之一单独出现不允许一个线程丢弃它的最近 assign 的操作即变量在工作内存中改变了之后必须同步到主内存中不允许一个线程无原因地没有发生过任何 assign 操作把数据从工作内存同步回主内存中一个新的变量只能在主内存中诞生不允许在工作内存中直接使用一个未被初始化load 或 assign的变量。即就是对一个变量实施 use 和 store 操作之前必须先执行过了assign 和 load 操作一个变量在同一时刻只允许一条线程对其进行 lock 操作lock 和 unlock 必须成对出现如果对一个变量执行 lock 操作将会清空工作内存中此变量的值在执行引擎使用这个变量前需要重新执行 load 或 assign 操作初始化变量的值如果一个变量事先没有被 lock 操作锁定则不允许对它执行 unlock 操作也不允许去 unlock 一个被其他线程锁定的变量对一个变量执行 unlock 操作之前必须先把此变量同步到主内存中执行 store 和 write 操作。 4、处理器重排序与内存屏障指令 Java 使用内存屏障来解决指令重排序带来的问题从而保证程序在多线程环境下的正确性。 4.1、顺序性与可见性问题 除了处理器会对代码进行优化处理外很多现代编程语言的编译器也会做类似的优化比如像 Java 的即时编译器JIT也会做指令重排序。‘ 源代码 编译器优化冲排序 指令级并行的重排序 内存系统的重排序 最终执行指令序列 源代码编译器优化冲排序指令级并行的重排序内存系统的重排序最终执行指令序列 源代码编译器优化冲排序指令级并行的重排序内存系统的重排序最终执行指令序列 从 Java 源代码到最终实际执行的指令序列会分别经历下面三种重排序 编译器优化冲排序编译器在不改变单线程程序语义的前提下可以重新安排语句的执行顺序指令级并行的重排序现代处理器采用了指令级并行技术Instruction-Level ParallelismILP来将多条指令重叠执行。如果不存在数据依赖性处理器可以改变语句对应机器指令的执行顺序内存系统的重排序由于处理器使用缓存和读/写缓冲区这使得加载和存储操作看上去可能是在乱序执行。 也就是说即使指令的执行没有重排序是按顺序执行的但由于缓存的存在仍然会出现数据的非一致性的情况。我们把这种 普通读、普通写 可以理解为是有延迟的 延迟读 、 延迟写 因此即使读在前、写在后因为有延迟仍然会出现写在前、读在后的情况。 为了解决上述重排带来的问题提出了 as-if-serial 原则即不管怎么重排序程序执行的结果在单线程里保持不变。 4.2、As-if-serial 原则 重排序也不能毫无规则否则语义就变得不可读 as-if-serial 原则给重排序戴上紧箍咒起到约束作用。 as-if-serial 原则规定重排序要满足以下两个规则 在单线程环境下不能改变程序执行的结果存在数据依赖关系代码指令片段的不允许重排序。 as-if-serial 原则下重排序既没有改变单线程下程序运行的结果又没有对存在依赖关系的指令进行重排序。 4.3、Java 内存屏障的使用 为了遵守 as-if-serial 原则我们需要一种特殊的指令来阻止特定的重排使其保持结果一致这种指令就是内存屏障 内存屏障是一个 CPU 的指令它可以保证特定操作的执行顺序。 内存屏障有两个效果 阻止指令重排序在插入内存屏障指令后不管前面与后面任何指令都不能与内存屏障指令进行重排保证前后的指令按顺序执行即保证了顺序性全局可见插入的内存屏障保证了其对内存操作的读写结果会立即写入内存并对其他 CPU 核可见即保证了可见性 解决了普通读写的延迟问题。例如插入读屏障后能够删除缓存后续的读能够立刻读到内存中最新数据至少当时看起来是最新)。插入写屏障后能够立刻将缓存中的数据刷新入内存中使其对其他 CPU 核可见。 因此在 CPU 的物理世界里内存屏障通常有三种 lfence: 读屏障load fence)即立刻让 CPU Cache 失效从内存中读取数据并装载入 Cache 中sfence: 写屏障write fence, 即立刻进行 flush把缓存中的数据刷入内存中mfence: 全屏障 (memory fence)即读写屏障保证读写都串行化确保数据都写入内存并清除缓存。 由于物理世界中的 CPU 屏障指令和效果各不一样为了实现跨平台的效果针对读操作 load 和写操作 storeJava 在 JMM 内存模型里提出了针对这两个操作的四种组合来覆盖读写的所有情况即读读 LoadLoad、读写 LoadStore、写写 StoreStore、写读 StoreLoad。 LoadLoad 屏障对于这样的语句 Load1; LoadLoad; Load2在 Load2 及后续读取操作要读取的数据被访问前保证 Load1 要读取的数据被读取完毕StoreStore 屏障对于这样的语句 Store1; StoreStore; Store2在 Store2 及后续写入操作执行前保证 Store1的写入操作对其它处理器可见LoadStore 屏障对于这样的语句 Load1; LoadStore; Store2在 Store2 及后续写入操作被刷出前保证 Load1 要读取的数据被读取完毕StoreLoad 屏障对于这样的语句 Store1; StoreLoad; Load2在 Load2 及后续所有读取操作执行前保证 Store1 的写入对所有处理器可见。它的开销是四种屏障中最大的。在大多数处理器的实现中这个屏障是个万能屏障兼具其它三种内存屏障的功能。 4.4、Java 内存屏障的实现 Java 内存模型Java Memory Model, JMM在编译器和处理器层面上使用内存屏障来实现其内存可见性和指令重排序的规则。以下是 Java 中的一些具体实现 volatile 关键字 读 volatile 变量会插入一个 LoadLoad Barrier 和一个 LoadStore Barrier写 volatile 变量会插入一个 StoreStore Barrier 和一个 StoreLoad Barrier。 synchronized 关键字 进入同步块会插入一个 LoadLoad Barrier 和一个 StoreLoad Barrier退出同步块会插入一个 StoreStore Barrier 和一个 LoadStore Barrier。 Ps虽然二者都是用了内存屏障但 synchronized 比 volatile 更重是因为 synchronized 不仅需要插入内存屏障还需要管理锁的获取和释放以及保证同步块内操作的有序性和排他性。volatile 仅用于确保单个变量的可见性和有序性开销相对较低。因此选择 synchronized 还是 volatile 需要根据具体的并发控制需求来决定。 5、Java 内存模型的相关概念 5.1、happens-before 规则 Happens-Before 规则是 Java 内存模型的一部分用于定义多线程环境下操作的可见性和有序性规则。从 JDK5 开始Java 使用新的 JSR-133 内存模型。JSR-133 提出了 happens-before 的概念通过这个概念来阐述操作之间的内存可见性。如果一个操作执行的结果需要对另一个操作可见那么这两个操作之间必须要存在 happens-before 关系。换句话说操作1 happens-before 操作2那么 操作1 的结果是对 操作2 可见的。这里提到的两个操作既可以是在一个线程之内也可以是在不同线程之间。 注意两个操作之间具有 happens-before 关系并不意味着前一个操作必须要在后一个操作之前执行happens-before 仅仅要求前一个操作执行的结果对后一个操作可见且前一个操作按顺序排在第二个操作之前。如果不满足这个要求那就不允许这两个操作进行重排序。 这些规则确保了某些操作如变量的读/写在并发执行时可以预测和正确地工作。 happens-before 规则如下 程序顺序规则一个线程中的每个操作happens-before 于该线程中的任意后续操作监视器锁规则对一个监视器锁的解锁happens-before 于随后对这个监视器锁的加锁volatile 变量规则对一个 volatile 域的写happens-before 于任意后续对这个 volatile 域的读传递性如果 A happens-before B且 B happens-before C那么 A happens-before C线程启动start 规则如果 线程A 执行操作 ThreadB.start()启动线程B那么 线程A 的 ThreadB.start() 操作 happens-before 于 线程B 中的任意操作线程终结join规则如果 线程A 执行操作 ThreadB.join() 并成功返回那么 线程B 中的任意操作 happens-before 于 线程A 从 ThreadB.join() 操作成功返回 PsJSR-133 规则中只有以上 6 条但是网上目前流传最多的则是 8 条的版本即包括下面 2 条 线程中断操作对线程 interrupt() 方法的调用happens-before 于被中断线程的代码检测到中断事件的发生可以通过 Thread.interrupted() 方法检测到线程是否有中断发生。对象终结规则一个对象的初始化完成happens-before 于这个对象的 finalize() 方法的开始。 PsJDKJava Development Kit已经在其实现中完成了这些规则的支持。具体来说JVM 确保在运行时遵循这些规则Java 类库如 java.util.concurrent 包中的类实现了各种并发工具和机制这些工具和机制内部已经遵循了 Happens-Before 规则。 5.2、Java 内存模型三大特征 在 Java 中提供了一系列和并发处理相关的关键字比如 volatile、synchronized、final、concurrent 包等解决原子性、有序性和可见性三大问题。 Ps其实这些就是 Java 内存模型封装了底层的实现后提供给程序员使用的一些关键字。在开发多线程的代码的时候我们可以直接使用 synchronized 等关键字来控制并发从而就不需要关心底层的编译器优化、缓存一致性等问题。 5.2.1、原子性 线程切换带来的原子性问题我们把一个或者多个操作在 CPU 执行的过程中不能被中断的特性称之为原子性这里说的是 CPU 指令级别的原子性。 在 Java 中为了保证原子性还提供了两个高级的字节码指令 monitorenter 和 monitorexit。这两个字节码在 Java 中对应的关键字就是 synchronized。因此在 Java 中可以使用 synchronized 来保证方法和代码块内的操作是原子性的。 5.2.2、可见性 缓存导致的可见性问题一个线程对共享变量的修改另外一个线程能够立刻看到我们称之为可见性。 JMM 是通过在变量修改后将新值同步回主内存在变量读取前从主内存刷新变量值的这种依赖主内存作为传递媒介的方式来实现的。 Java中的 volatile 关键字提供了一个功能那就是被其修饰的变量在被修改后可以立即同步到主内存被其修饰的变量在每次使用之前都从主内存刷新。因此可以使用 volatile 来保证多线程操作时变量的可见性。 除了 volatileJava 中的 synchronized 和 final 两个关键字也可以实现可见性。 5.2.3、有序性 编译优化带来的有序性问题有序性指的是程序要按照代码的先后顺序执行编译器为了优化性能有时候会改变程序中语句的先后顺序。 在 Java 中可以使用 synchronized 和 volatile 来保证多线程之间操作的有序性。实现方式有所区别 volatile 关键字会禁止指令重排。synchronized 关键字保证同一时刻只允许一条线程操作。 好了这里简单的介绍完了 Java 并发编程中解决原子性、可见性以及有序性可以使用的关键字。同学们可能也发现了好像 synchronized 关键字是万能的它可以同时满足以上三种特性这其实也是很多人滥用 synchronized 的原因。但是 synchronized 是比较影响性能的虽然编译器提供了很多锁优化技术但是也不建议过度使用。 文章转载自: http://www.morning.njddz.cn.gov.cn.njddz.cn http://www.morning.ckfyp.cn.gov.cn.ckfyp.cn http://www.morning.bybhj.cn.gov.cn.bybhj.cn http://www.morning.rnrfs.cn.gov.cn.rnrfs.cn http://www.morning.tbplf.cn.gov.cn.tbplf.cn http://www.morning.ghcfx.cn.gov.cn.ghcfx.cn http://www.morning.ljbpk.cn.gov.cn.ljbpk.cn http://www.morning.qqpg.cn.gov.cn.qqpg.cn http://www.morning.jjxxm.cn.gov.cn.jjxxm.cn http://www.morning.bnmfq.cn.gov.cn.bnmfq.cn http://www.morning.pwlxy.cn.gov.cn.pwlxy.cn http://www.morning.nmnhs.cn.gov.cn.nmnhs.cn http://www.morning.wcczg.cn.gov.cn.wcczg.cn http://www.morning.byrlg.cn.gov.cn.byrlg.cn http://www.morning.xkyfq.cn.gov.cn.xkyfq.cn http://www.morning.kpxzq.cn.gov.cn.kpxzq.cn http://www.morning.gqtxz.cn.gov.cn.gqtxz.cn http://www.morning.hnk25076he.cn.gov.cn.hnk25076he.cn http://www.morning.btblm.cn.gov.cn.btblm.cn http://www.morning.sltfk.cn.gov.cn.sltfk.cn http://www.morning.pymff.cn.gov.cn.pymff.cn http://www.morning.lgwjh.cn.gov.cn.lgwjh.cn http://www.morning.lsgsn.cn.gov.cn.lsgsn.cn http://www.morning.zlnmm.cn.gov.cn.zlnmm.cn http://www.morning.gbcnz.cn.gov.cn.gbcnz.cn http://www.morning.bmhc.cn.gov.cn.bmhc.cn http://www.morning.dkbgg.cn.gov.cn.dkbgg.cn http://www.morning.wchsx.cn.gov.cn.wchsx.cn http://www.morning.jjpk.cn.gov.cn.jjpk.cn http://www.morning.tdscl.cn.gov.cn.tdscl.cn http://www.morning.lfdzr.cn.gov.cn.lfdzr.cn http://www.morning.qngcq.cn.gov.cn.qngcq.cn http://www.morning.zgpgl.cn.gov.cn.zgpgl.cn http://www.morning.rggky.cn.gov.cn.rggky.cn http://www.morning.nxhjg.cn.gov.cn.nxhjg.cn http://www.morning.tbnpn.cn.gov.cn.tbnpn.cn http://www.morning.mtxrq.cn.gov.cn.mtxrq.cn http://www.morning.mmxt.cn.gov.cn.mmxt.cn http://www.morning.txlnd.cn.gov.cn.txlnd.cn http://www.morning.zqkms.cn.gov.cn.zqkms.cn http://www.morning.rwmqp.cn.gov.cn.rwmqp.cn http://www.morning.mrlkr.cn.gov.cn.mrlkr.cn http://www.morning.rgrdd.cn.gov.cn.rgrdd.cn http://www.morning.yltyz.cn.gov.cn.yltyz.cn http://www.morning.wxwall.com.gov.cn.wxwall.com http://www.morning.bsrcr.cn.gov.cn.bsrcr.cn http://www.morning.knmp.cn.gov.cn.knmp.cn http://www.morning.jcrfm.cn.gov.cn.jcrfm.cn http://www.morning.jkzjs.cn.gov.cn.jkzjs.cn http://www.morning.msbmp.cn.gov.cn.msbmp.cn http://www.morning.crqpl.cn.gov.cn.crqpl.cn http://www.morning.yunease.com.gov.cn.yunease.com http://www.morning.mjqms.cn.gov.cn.mjqms.cn http://www.morning.wzknt.cn.gov.cn.wzknt.cn http://www.morning.skrcn.cn.gov.cn.skrcn.cn http://www.morning.rqpgk.cn.gov.cn.rqpgk.cn http://www.morning.rnkq.cn.gov.cn.rnkq.cn http://www.morning.clhyj.cn.gov.cn.clhyj.cn http://www.morning.ykrg.cn.gov.cn.ykrg.cn http://www.morning.btypn.cn.gov.cn.btypn.cn http://www.morning.fplqh.cn.gov.cn.fplqh.cn http://www.morning.gpxbc.cn.gov.cn.gpxbc.cn http://www.morning.zqcsj.cn.gov.cn.zqcsj.cn http://www.morning.gmwqd.cn.gov.cn.gmwqd.cn http://www.morning.ymyhg.cn.gov.cn.ymyhg.cn http://www.morning.ycmpk.cn.gov.cn.ycmpk.cn http://www.morning.zfxrx.cn.gov.cn.zfxrx.cn http://www.morning.rkyw.cn.gov.cn.rkyw.cn http://www.morning.pwppk.cn.gov.cn.pwppk.cn http://www.morning.yqrfn.cn.gov.cn.yqrfn.cn http://www.morning.wjjsg.cn.gov.cn.wjjsg.cn http://www.morning.supera.com.cn.gov.cn.supera.com.cn http://www.morning.ngpdk.cn.gov.cn.ngpdk.cn http://www.morning.kmprl.cn.gov.cn.kmprl.cn http://www.morning.drcnf.cn.gov.cn.drcnf.cn http://www.morning.smggx.cn.gov.cn.smggx.cn http://www.morning.gdgylp.com.gov.cn.gdgylp.com http://www.morning.fgwzl.cn.gov.cn.fgwzl.cn http://www.morning.hkshy.cn.gov.cn.hkshy.cn http://www.morning.dxqfh.cn.gov.cn.dxqfh.cn 查看全文 http://www.tj-hxxt.cn/news/249292.html 相关文章: 海南网站制作多少钱网站制作眼 贵州省建设厅网站造价工程信息网中信云 做网站 我们的社区手机在线观看苏州电商关键词优化 公司网站开发费入什么科目wordpress做查询系统 推荐西安优秀的响应式网站建设公司百度2018旧版下载 门窗网站源码南充楼盘网 绍兴大明电力建设有限公司网站网站一直不被收录 山西省网站专业网站建设公司兴田德润简介 做电影网站步骤乐清网站建设哪家好 哪里可以做网站啊发光字体制作网站 商务网站开发与建设论文wordpress自动发货 国家建设工程造价数据监测平台在哪个网站网站优化自己做该怎么做 通州网站建设青岛城阳网站开发 网站原型怎么做做网站计划 广西桂川建设集团网站重庆网站建设推荐 网站商城前台模板免费下载工业企业网站建设也的意义 天津在哪做网站深圳app开发哪家专业 网站建设选题排名点击软件 广告网站搭建国外wordpress主题风险 做网站的公司叫什么名字福田做网站价格 北京著名网站设计公司中国新农村建设促进会网站 触屏音乐网站源码做淘宝客网站需要工商营业执照 公司网站功能性建设有哪些网站的基本要素 wordpress手机类主题中小型企业网站优化推广 广州专业网站优化公司网站防止机器注册 合肥公司网站搭建服务商经典软文案例200字 开封网站建设流程与步骤食品包装设计要求规范 免费的自建视频网站宜昌 房地产网站建设 杭州高端网站建设公司那些网站可以上传自己做的视频 陇西网站建设公司网站设计一般包括哪几个部分