当前位置: 首页 > news >正文

开发一个h5网站多少钱网站建设与服务技能实训心得体会

开发一个h5网站多少钱,网站建设与服务技能实训心得体会,济南建设工程招投标管理网,网页制作和设计实验目的【0】README0.1#xff09;本文部分文字描述转自“深入理解jvm”#xff0c;旨在学习“java内存模型与线程” 的基础知识#xff1b;【1】概述1#xff09;并发处理的广泛应用是使得 Amdahl 定律代替摩尔定律称为计算机性能发展源动力的根本原因#xff1b;2#xff09;A…【0】README0.1本文部分文字描述转自“深入理解jvm”旨在学习“java内存模型与线程” 的基础知识【1】概述1并发处理的广泛应用是使得 Amdahl 定律代替摩尔定律称为计算机性能发展源动力的根本原因2Amdahl 定律该定律通过系统中并行化与串行化的比重来描述多处理器系统能获得的运算加速能力3摩尔定律该定律用于描述处理器晶体管数量与运行效率间的发展关系Conclusion这两个定律的更替代表了近年来硬件发展从追求处理器频率到追求多核心并行处理的发展过程【2】硬件的效率与一致性1高速缓存干货——引入高速缓存1.1problem由于计算机的存储设备与处理器的运算速率有几个数量级的差距1.2solution引入一层读写速度尽可能接近处理器速度的高速缓存cache 来作为内存与处理器间的缓冲 将运算需要使用到的数据复制到缓存中让运算能快速进行当运算结束后再从缓冲同步回内存中这样处理器就无须等待缓慢的内存读写了 2缓存的引入产生了一个新问题——缓存一致性 在多处理器系统中每个处理器都有自己的高速缓存而它们又共享同一主内存如下图所示2.1问题描述problem 当多个处理器的运算任务都涉及到同一块内存区域时将可能导致各自的缓存数据不一致那同步到内存时以谁的数据为准呢2.2solution 需要各个处理器遵循一些协议在读写时要根据协议来进行操作这类协议有 MSI MESI等。2.3内存模型 可以理解为 在特定的操作协议下对特定的内存或高速缓存进行读写访问的过程抽象干货——java内存模型定义 3乱序执行 为了使得处理器内部的运算单元能够被尽量使用处理器可能对输入代码进行乱序执行优化处理器会在计算之后将乱序执行的结果重组保证该结果与顺序执行的结果是一致的【3】java内存模型0intro to java内存模型java虚拟机规范试图定义一种java内存模型java memory model来屏蔽掉各种硬件和操作系统的内存访问差异以实现让java程序在各种平台下都能达到一致的内存访问效果【3.1】主内存与工作内存1java内存模型的主要目标定义程序中各个变量的访问规则即在虚拟机中将变量存储到内存和从内存中读取变量这样的底层细节2java内存模型规定了所有的变量都存储在主内存中。2.1每条线程还有自己的工作内存 线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝线程对变量的所有操作读取赋值都必须在工作内存中进行而不能直接读写内存中的变量。不同的线程之间也无法直接访问对方工作内存中的变量;干货——每条线程还有自己的工作内存工作内存定义2.2线程间变量值的传递均需要通过主内存来完成线程、内存、工作内存三者关系如下所示 3这里所讲的主内存工作内存与前面讲的 java内存区域中的java堆栈方法区等并不是同一个层次的内存划分这两者基本没有关系3.1如果硬要扯上关系则主内存主要对应于java堆中的对象实例数据部分而工作内存则对应于虚拟机栈中的部分区域3.2更低层次上说主内存就直接对应于物理硬件的内存而为了获得更好的运行速度虚拟机可能会让工作内存优先存储于寄存器和高速缓存中因为程序运行时主要访问读写的是工作内存 【3.2】内存间交互操作1关于主内存与工作内存间的交互协议即一个变量如何从主内存拷贝到工作内存如何从工作内存同步回主内存java内存模型中定义了以下8种操作operations干货——java内存模型中定义了以下8种操作o1lock锁定作用于主内存的变量它把一个变量标识为一条线程独占的状态o2unlock解锁作用于主内存的变量它把一个处于锁定状态的变量释放出来释放后的变量才可以被其他线程锁定o3read读取作用于主内存的变量它把一个变量的值从主内存传输到线程的工作内存中以便随后的load 动作使用o4load载入作用于工作内存的变量 它把 read 操作从主内存中得到的变量放入工作内存的变量副本中o5use使用作用于工作内存的变量它把工作内存中一个变量的值传递给执行引擎每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作o6assign赋值作用于工作内存的变量它把一个从执行引擎接收到的值赋给工作内存的变量每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作o7store存储作用于工作内存的变量 它把工作内存中一个变量的值传送到主内存中以便随后的write操作使用o8write写入作用于主内存的变量 它把store操作从工作内存中得到的变量的值放入主内存的变量中 2相关操作2.1把变量从主内存复制到工作内存顺序执行read和load操作目的地是工作内存2.2把变量从工作内存同步回主内存顺序执行store和write操作目的地是主内存Attentionjava内存模型只要求上述两个操作必须按顺序执行没有保证是连续执行即read和 load 之间store和 write之间可以插入其他指令干货——java内存模型只要求上述两个操作必须按顺序执行没有保证是连续执行它们之间还可以插入其他指令 3java内存模型还规定了在执行上述8种基本操作时必须满足如下规则rulesr1不允许read和 loadstore 和 write操作之一单独出现即不允许一个变量从主内存读取了但工作内存不接受或者从工作内存发起回写了但主内存不接受的情况出现r2不允许一个线程丢弃它的最近的assign操作即变量在工作内存中改变了之后必须把该变化同步回主内存r3不允许一个线程无原因地没有发生过任何 assign操作把数据从线程的工作内存同步回主内存中r4一个新变量只能在主内存中诞生不允许在工作内存中直接使用一个未被初始化的变量换句话说对一个变量实施 usestore操作前必须先执行过 assign 和 load 操作r5一个变量在同一个时刻只允许一个线程对其进行lock 操作但lock操作可以被同一条线程重复执行多次多次执行 lock后只有执行相同次数的unlock 操作变量才会被解锁r6如果对一个变量执行lock 操作那将会清空工作内存中此变量的值在执行引擎使用这个变量前需要重新执行 load 或 assign 操作初始化变量的值r7如果一个变量事先没有被lock操作锁定那就不允许对它执行unlock操作也不允许去 unlock 一个被其他线程锁定住的变量r8对一个变量执行unlock 变量前必须先把此变量同步回主内存中执行store write操作Conclusion 这8种内存访问操作以及上述规则限定再加上稍后介绍的对 volatile 的一些特殊规定就已经完全确定了java 程序中哪些内存访问操作在并发下是安全的 【3】 对于volatile型变量的特殊规则1当一个变量定义为volatile后它具备两种特性charactersc1保证此变量对所有线程的可见性这里的可见性指当一条线程修改了这个变量的值新值对于其他线程来说是可以立即得知的。而普通变量做不到这一点其在线程间传递需要通过主内存来完成干货——这就是为什么会出现数据的脏读c2对于volatile变量的可见性有一些误解 volatile变量对所有线程都是可见的对volatile变量所有的写操作都能立刻反应到其他线程中即volatile变量在各个线程中是一致的所有基于 volatile变量的运算在并发下是安全的。上述语句中的错误在于并不能得出“基于 volatile变量的运算在并发下是安全的”这个结论。 2虽然volatile变量在各个线程的工作内存中不存在一致性问题但java里面的运算并非原子操作导致 volatile变量的运算在并发下一样是不安全的。2.1看个荔枝public class VolatileTest {public static volatile int race 0;public static void increase() {race;}public static final int THREADS_COUNT 20;public static void main(String[] args) {Thread[] threads new Thread[THREADS_COUNT];for (int i 0; i threads.length; i) {threads[i] new Thread(new Runnable() {Overridepublic void run() {for (int j 0; j 10000; j) {increase();}}});threads[i].start();}// 等待所有累计线程都endingwhile(Thread.activeCount() 1) {Thread.yield();}System.out.println(race);} } 对以上执行结果的分析Analysis A1以上代码的正确输出结果是20000 而执行的结果每次都不一样且都小于20000A2用javap 反编译命令得到如下字节码发现increase方法对应4条字节码指令return指令不算 对以上字节码的分析Analysis A1当 getstatic指令 把 race 的值取到操作栈顶时volatile关键字保证了 race的值在此时是正确的但是在执行 iconst_1, iadd 这些指令的时候其他线程可能已经把race 的值加大了而在操作栈顶的值就变成了过期的数据所以 putstatic 指令执行后就可能把较小的race 值同步回主内存中A2客观上说在这里使用 字节码来分析并发问题不是很严谨。因为即使编译出来只有一条字节码指令也不意味着执行这条指令就是一个原子操作。一条字节码指令也可能会转化成若干条本地机器码指令此处使用 -XX:PrintAssembly 参数输出反汇编来分析会更加严谨干货——因为即使编译出来只有一条字节码指令也不意味着执行这条指令就是一个原子操作 3由于volatile变量只能保证可见性在不符合以下两条规则的运算场景中我们仍然要通过加锁来保证原子性scene1运算结果并不依赖变量的当前值或者能够确保只有单一的线程修改变量的值scene2变量不需要与其他的状态变量共同参与不变约束 3.1看个荔枝使用volatile变量来控制并发// 使用volatile变量来控制并发 public class VolatileVariableTest {volatile boolean shutdownRequested; // volatile变量public void shutdown() {shutdownRequested true;}public void doWork() {while(!shutdownRequested) {// do sth.}} 3.2使用volatile变量的第二个语义是禁止指令重排序优化普通变量仅仅会保证在该方法的执行过程中所有依赖赋值结果的地方都能获取到正确的结果而不能保证变量赋值操作的顺序与程序代码中的执行顺序一致。因为在一个线程的 方法执行过程中无法感知到这点这也就是java 内存模型中描述的所谓的 “线程内表现为串行的语义”干货——volatile可以禁止指令重排序优化// 指令重排序演示伪代码public void instruct_reorder() {Map configOptions;char[] configText;// 此变量必须为 volatilevolatile boolean initialized false;// 假设以下代码在线程A 中执行// 模拟读取配置信息当读取完成后将 initialized 设置为true 已通知其他线程配置可用configOptions new HashMap();configText readConfigFile(filename);processConfigOptions(configText, configOptions);initialized true;// 假设以下代码在线程B 中执行// 等待initialized 为true代表线程A 已经把配置信息初始化完成while(!initialized) {sleep();}// 使用线程A 中初始化好的配置信息do_sth_with_config();} 对以上代码的分析Analysis如果定义initialized变量没有使用volatile修饰就可能会由于指令重排序的优化导致位于线程A 中最后一句代码“initializedtrue”被提前执行这样在线程B中使用配置信息的代码就可能出现错误而volatile关键字则可以避免此类情况的发生 3.3再看个荔枝分析volatile关键字是如何禁止指令重排序优化的以下代码是一段单例模式代码可以观察加入 volatile和未加入volatile关键字时 所生成汇编代码的差别如何获得JIT的汇编代码参考4.2.7// 单例模式分析volatile关键字是如何禁止指令重排序优化的 public class Singleton {private volatile static Singleton instance;public static Singleton getInstance() {if(instance null) {synchronized (Singleton.class) { // 同步块if(instance null) {instance new Singleton();}}}return instance;}public static void main(String[] args) {Singleton.getInstance();} }Attention如何对Class字节码文件进行反汇编【3.4】对于long 和 double 型变量的特殊规则1java内存模型要求lock unlock read load assign usestorewrite这8个操作都具有原子性 但对于64位的数据类型long和double在模型中特别定义了一条相对宽松的规定允许虚拟机将没有被 volatile修饰的64位数据的读写操作划分为两次32位的操作来进行即允许虚拟机实现选择可以不保证64位数据类型的load storeread和write这4个操作的原子性这点就是所谓的 long 和double 的非原子性协定2这项宽松的规定所导致的problem如果有多个线程共享一个并未声明为 volatile的long 或 double类型的变量并且同时对它们进行读取和修改操作那么某些线程可能会读取到一个既非原值也不是其他线程修改值的代表了半个变量的数值3不过这种读取到的“半个变量”的case非常罕见因为java内存模型虽然允许虚拟机不把long 和 double 变量的读写实现成原子操作但允许虚拟机选择把 这些操作实现为具有原子性的操作而且还强烈建议虚拟机这样实现干货——不过这种读取到的“半个变量”的case非常罕见【3.5】原子性可见性与有序性0intro java内存模型是围绕着在并发过程中如何处理原子性 可见性和有序性这3个特征来建立的1原子性由于java内存模型来直接保证的原子性变量操作包括 readloadassignusestore和write我们大致认为基本数据类型的访问读写数据是具备原子性的。1.1同步块——synchronized关键字如果应用场景需要一个更大范围的原子性保证java内存模型还提供了lock 和 unlock 操作来满足这些需求尽管虚拟机没有把lock 和 unlock 操作直接开放给用户使用但是却提供了更高层次的字节码指令 monitorenter 和 monitorexit 来隐式地使用这两个操作1.2这两个字节码指令反映到java代码中就是同步块——synchronized关键字因此在synchronized块之间的操作也具备原子性 2可见性可见性指当一个线程修改了共享变量的值其他能够立即得知这个修改。2.1java内存模型是通过在变量修改后将新值同步回主内存在变量读取前从主内存刷新变量值这种依赖主内存作为传递媒介的方式来实现可见性的无论是普通变量还是volatile变量都是如此2.2普通变量与 volatile变量的区别是volatile的特殊规则保证了新值能立即同步到主内存以及每次使用前立即从主内存刷新所以volatile保证了多线程操作时变量的可见性普通变量则不能保证这一点2.3java还有两个关键字实现可见性 synchronized 和 final 2.3.1同步块的可见性 是由对一个变量执行unlock 操作前必须先把此变量同步回主内存中2.3.2而final关键字的可见性被final修饰的字段在构造器中一旦初始化完成并且构造器没有把this 的引用传递出去那在其他线程中就能看见final 字段的值。2.3.3看个荔枝// final 可见性测试 public class FinalVisibilityTest {public static final int i;public final int j;static {i 0;// do sth}{// 也可以选择在构造函数中初始化j 0;// do sth} } 对以上代码的分析Analysis变量i 和 j 都具备可见性它们无须同步就能被其他线程正确访问 3有序性3.1java程序中天然的有序性总结为一句话如果在本线程内观察所有的操作都是有序的如果在一个线程中观察另一个线程所有的操作都是无序的。前半句是指 线程内表现为串行的语义后半句是指指令重排序现象和工作内存与主内存同步延迟现象3.2volatile和 synchronized关键字保证了线程间操作的有序性volatile关键字本身就包含了禁止指令重排序的语义而synchronized则是由 一个变量在同一时刻只允许一条线程对其进行lock 操作这条规则获得的这条规则决定了持有同一个锁的两个同步块只能串行地进入 【3.6】先行发生原则1先行发生原则定义先行发生是 java内存模型中定义的两项操作之间的偏序关系如果说操作A 先行发生于操作B其实就是说在发生操作B之前操作A产生的影响能被操作B观察到 影响包括 修改了内存中共享变量的值发送了消息调用了方法等干货——先行发生原则定义2看个荔枝如何理解 “影响包括 修改了内存中共享变量的值发送了消息调用了方法等”// 先行发生 原则 public class AheadOccurTest {int i 0;int j 0;public void test() {// 以下操作在线程A中执行i 1;// 以下操作在线程 B 中执行j i;// 以下操作在线程 C 中执行i 2;} }对以上代码的分析Analysis线程C 出现在 线程A 和 B之间 但线程C 和 B 并没有先行发生关系那j的值 会是多少答案是不确定的3下面是java内存模型下一些天然的先行发生关系这些先行发生关系无须任何同步器协助就已经存在可以在编码中直接使用3.1程序次序规则在一个线程内按照程序代码顺序书写在前面的操作先行发生于书写在后面的操作准确地说应该是控制流顺序3.2管程锁定规则一个unlock操作先行发生于后面对同一个锁的lock操作这里必须强调的是同一个锁而后面是指时间上的先后顺序3.3volatile变量规则对一个volatile变量的写操作先行发生于后面对这个变量的读操作这里的后面是指时间上的先后顺序3.4线程启动规则Thread对象的start() 方法先行发生于此线程的每一个动作3.5线程终止规则线程中的所有操作都先行发生于对此线程的终止检测可以通过Thread.join() 方法结束Thread.isAlive() 的返回值等手段检测到线程已经终止运行3.6线程中断规则对线程interrupt() 方法的调用先行发生于被中断线程的代码检测到中断事件的发生可以通过 Thread.interrrupted() 方法检测到是否有中断发生3.7对象终结规则一个对象的初始化完成先行发生于它的finalize() 方法的开始3.8传递性如果操作A 先行发生于操作B 操作B 先行发生于操作C那就可以得出操作A 先行发生于 操作C的结论 4看个荔枝如何使用这些规则去判定操作间是否具备顺序性对于读写共享变量的操作来说就是线程是否安全// 利用先行发生 原则 // 判定操作间是否具备顺序性对于读写共享变量的操作来说就是线程是否安全 public class AheadOccurTest2 {private int value 0;public void setValue(int value) {this.value value; }public int getValue() {return value;}Integer i 0; } 对以上代码的分析AnalysisA1problem假设线程A 先调用了 setValue(1) 之后线程B 调用了同一个对象的getValue() 那么线程B 收到的value是什么A2可以判定尽管线程A在操作时间上先于线程B 但是无法确定线程B 中“getValue()” 方法的返回结果换句话说这里面的操作不是线程安全的A3solution我们至少有两种简单的解决方案 solution1要么把getter 和  setter方法都定义为 synchronized方法这样就可以套用管程锁定规则solution2要么把value定义为 volatile变量由于setter方法对value的修改不依赖于 value的原值满足volatile关键字使用场景这样就可以套用volatile变量规则来实现先行发生关系 A4得出结论一个操作时间上的先发生 不代表这个操作会是先行发生那如果一个操作先行发生是否就能推导出这个操作必定是 时间上的先行发生呢 显然推导不出来。一个典型的荔枝就是多次提到的“指令重排序”。 A4.1看个荔枝// 以下操作在同一个线程中执行 int i 1; int j 2;对上述代码的分析Analysis 根据程序次序规则 int i 1 的操作先行发生于 int j 2但 int j 2 完全可能先被处理器执行这并不影响先行发生原则的正确性 Conclusion以上两个实例得出结论时间先后顺序与先行发生原则之间基本没有太大的关系所以我们衡量并发安全问题的时候不要受到时间顺序的干扰一切必须以先行发生原则为准 【4】java 与线程【4.1】线程的实现0intro0.1线程是比进程更轻量级的调度执行单位 线程的引入可以把一个进程的资源分配和执行调度分开各个线程既可以共享进程资源内存地址文件IO等又可以独立调度线程是CPU 调度的基本单位0.2线程实现的3种方式使用内核线程实现使用用户线程实现使用用户线程加轻量级进程混合实现干货——线程实现的3种方式使用内核线程实现使用用户线程实现使用用户线程和轻量级进程混合实现 1使用内核线程实现1.1内核线程KLTKernel-Level Thread就是直接由操作系统内核下称内核支持的线程这种线程由内核来完成线程切换内核通过操纵调度器对线程进行调度并负责将线程的任务映射到各个处理器上。干货——内核线程和轻量级进程的定义1.2程序一般不会直接去使用内核线程而是去使用内核线程的一种高级接口——轻量级进程Light Weight Process, LWP轻量级进程就是我们通常意义上讲的线程由于每个轻量级线程都由一个内核线程支持因此只有先支持内核线程才能有轻量级进程。这种轻量级进程与内核线程间1:1 的关系称为一对一的线程模型如下图所示干货——引入轻量级进程 1.3轻量级进程有局限性 1.3.1首先由于是基于内核线程实现的所以各种线程操作如创建析构及同步都需要进行系统调用 而系统调用的代价相对较高需要在用户态和内核态中来回切换1.3.2其次每个轻量级进程都需要有一个内存线程的支持因此轻量级进程要消耗一定的内核资源如内核线程的栈空间因此一个系统支持轻量级进程的数量是有限的 2使用用户线程实现已经被Deprecated3使用用户线程加轻量级进程混合实现3.1在该实现方式下既存在用户线程也存在轻量级进程3.2用户线程还是完全建立在用户空间中因此用户线程的创建切换析构等操作依然廉价并且可以支持大规模的用户线程并发3.3操作系统提供支持的轻量级进程则作为用户线程和内核线程之间的桥梁这样可以使用内核提供的线程调度功能及处理器映射并且用户线程的系统调用要通过轻量级线程来完成大大降低了整个进程被完全阻塞 的风险干货——操作系统提供支持的轻量级进程则作为用户线程和内核线程之间的桥梁3.4在这种混合模式中用户线程与轻量级进程的数量比是不定的即为 NM 的关系如下图所示 这种就是多对多的线程模型 【4.2】java线程调度1线程调度定义是指系统为线程分配处理器使用权的过程主要调度方式有协同式线程调度 和 抢占式线程调度干货——线程调度定义 主要调度方式干货——请注意协同式线程调度和抢占式线程调度的区别2使用协同式线程调度的多线程系统线程的执行时间由线程本身来控制线程把自己的工作执行完以后要主动通知系统切换到另外一个线程上2.1其好处是实现简单而且由于线程要把自己的事情干完后才会进行线程切换切换操作读线程自己是可知的所以没有什么线程同步的问题2.2其坏处是线程执行时间不可控制甚至如果一个线程编写有问题一直不告诉系统进行线程切换那么程序就会一直阻塞在那里 3使用抢占式线程调度的多线程系统那么每个线程将由系统来分配执行时间线程的切换不由线程本身来决定3.1java使用的方式就是 抢占式线程调度方式3.2虽然java 线程调度是系统自动完成的 但我们还是可以建议系统给某些线程多分配一点执行时间另外一些线程则可以少分配一点——这项操作可以通过设置线程优先级来完成干货——设置java 线程优先级3.3.不过线程优先级并不是太靠谱因为java的线程是通过映射到系统的原生线程上来实现的所以线程调度最终还是取决于 操作系统虽然现在很多os 都提供了线程优先级但不见得和 能与 java线程的优先级一一对应如 Solaris中有 2^32 种优先级而windows只有7种 干货——java的线程优先级并不是太靠谱3.4下表显示了 java线程优先级 与 windows 线程优先级之间的对应关系 补充-ComplementaryC1上文说到的“java线程优先级并不是太靠谱”不仅仅是在说一些平台上不同的优先级实际会变得相同这一点还有其他case 让我们不能太依赖优先级优先级可能会被系统自行改变。干货——优先级可能会被系统自行改变C2如在windows 中存在一个称为 “优先级推进器”的功能作用是 当系统发现一个线程执行得特别勤奋的话可能会越过线程优先级去为它分配执行时间 【4.3】状态转换1java定义了6种状态status干货——java定义了6种线程状态 1.1新建New创建后尚未启动的线程处于这个状态1.2运行RunnableRunable包括了os 线程状态中的 Running 和 Ready也就是处于 此状态的线程有可能正在执行也有可能正在等待着CPU 为它分配执行时间1.3无限期等待Waiting处于这种状态的线程不会被分配CPU执行时间它们要等待被其他线程显式的唤醒。以下方法会让线程陷入无限期的等待状态methods m1没有设置Timeout参数的Object.wait()方法m2没有设置Timeout参数的 Thread.join() 方法m3LockSupport.park() 方法 1.4限期等待Timed Waiting处于这种状态的线程也不会被分配CPU 执行时间不过无需等待被其他线程显式唤醒在一定时间之后它们会由系统自动唤醒。以下方法会让线程进入限期等待状态methods m1Thread.sleep() 方法m2设置了Timeout参数的Object.wait()方法m3设置了Timeout参数的 Thread.join() 方法m4LockSupport.parkNanos() 方法m5LockSupport.parkUntil() 方法 1.5阻塞Blocked线程被阻塞了 阻塞状态与等待状态的区别是阻塞状态在等待着获取到一个排他锁这个事件将在另外一个线程放弃这个锁的时候发生而等待状态则是在等待一段时间或者唤醒动作的发生。在程序等待进入同步区域的时候 线程将进入这种状态1.6结束Terminated已经终止线程的线程状态线程已经结束执行 2以上6种状态会相互转换转换关系如下图所示
http://www.huolong8.cn/news/88987/

相关文章:

  • 做网站的过程装饰行业网站模板
  • 安徽网站设计方案知名企业公司
  • 建一个网站需要多少钱?网站专题素材
  • 邓州网站优化想做游戏代理去哪里找
  • 有一个做ppt的网站wordpress样式表
  • 网站建站制作深圳做外贸的公司
  • 谷歌网站优化推广wordpress程序做mip步骤
  • 推进门户网站建设方案朝阳网站关键词优化
  • 威海市建设局官方网站接做网站的项目
  • 网站建设成本分析有没有和小孩做的网站
  • 网站常见攻击网站建设教程百度云
  • 济南制作网站制作公司策划罗湖商城网站建设哪家公司便宜点
  • 山东省建筑住房和城乡建设厅网站wordpress运行php代码
  • 全国有哪些做服装的网站网站安全狗卸载卸载不掉
  • 深圳石岩做网站狼雨seo网站排名查询
  • 网站建设 虚拟化微信登录wordpress免费
  • 毕业设计 网站建设选题工具类网站开发
  • 邢台建设企业网站费用中国建设银行个人网上银行登录
  • 小本本教你做网站建设网站需要什么条件
  • 自己做网站买东西wordpress调用单页
  • 手机网站单页面全国做网站公司前十名
  • php如何创建站点删除自豪的采用wordpress
  • 可信网站验证长沙最新招聘
  • 威海网站优化公司江西省宜春市建设局网站
  • 用html制作购物网站网站内容注意事项
  • 想查客户信息做网站软件开发设计文档示例
  • 用书籍上的文章做网站更新2018年临沂建设局网站
  • 自己做网站需要多少费用做网站可以用海外空间吗
  • 网站开发z亿玛酷1负责校园文化设计公司公司排名
  • 西安网站设计费用做网络歌手的网站