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

外贸做零售的网站连云港吧

外贸做零售的网站,连云港吧,站酷设计网站首页,摄影网站制作设计大家好#xff0c;我是栗筝i#xff0c;这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 016 篇文章#xff0c;在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验#xff0c;并希望进… 大家好我是栗筝i这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 016 篇文章在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验并希望进一步完善自己对整个 Java 技术体系来充实自己的技术栈的同学。与此同时本专栏的所有文章也都会准备充足的代码示例和完善的知识点梳理因此也十分适合零基础的小白和要准备工作面试的同学学习。当然我也会在必要的时候进行相关技术深度的技术解读相信即使是拥有多年 Java 开发经验的从业者和大佬们也会有所收获并找到乐趣。 – Java 集合框架Java Collections Framework为开发者提供了一套强大且灵活的数据结构和算法工具使得数据管理和操作变得更加高效和简洁。在多线程环境中如何在保证线程安全的同时保持集合操作的高效性成为了一个至关重要的课题。为此Java 提供了一系列并发集合类其中 CopyOnWrite 系列集合因其独特的“写时复制”机制成为了解决并发读写问题的一种有效方案。 CopyOnWrite 集合类主要包括 CopyOnWriteArrayList 和 CopyOnWriteArraySet。它们通过在每次修改集合时创建一个新副本从而保证了读操作的无锁化这种设计极大地提高了读操作的性能同时也简化了开发者的使用难度。然而写时复制的特性也带来了一定的内存开销和写操作的性能代价。因此了解其工作原理和适用场景对于我们在实际开发中选择合适的集合类至关重要。 在本文中我们将深入探讨 CopyOnWrite 集合的实现原理、优缺点以及适用场景帮助读者全面理解和正确使用这些集合类。无论是编写高性能的多线程应用程序还是解决复杂的并发数据访问问题掌握 CopyOnWrite 集合的使用技巧都将为您的开发工作带来极大的助益。 文章目录 1、写时复制的介绍2、写时复制的实现2.1、CopyOnWriteArrayList 数据结构2.2、CopyOnWriteArrayList 读操作2.2、CopyOnWriteArrayList 写时复制2.2.1、add() 函数2.2.2、remove() 函数2.2.3、set() 函数 2.3、CopyOnWriteArraySet 的实现 3、写实复制的特性3.1、读多写少3.2、弱一致性3.3、连续存储3.3.1、数组容器3.3.3、非数组容器 1、写时复制的介绍 写时复制Copy-on-Write简称COW是一种计算机程序设计领域的优化策略。 其核心思想是如果有多个调用者同时请求相同资源如内存或磁盘上的数据存储他们会共同获取相同的指针指向相同的资源直到某个调用者试图修改资源的内容时系统才会真正复制一份专用副本给该调用者而其他调用者所见到的最初的资源仍然保持不变。这一过程对其他的调用者都是透明的。 当对容器进行写操作这里的写可以理解为 “增、删、改”时为了避免读写操作同时进行而导致的线程安全问题 我们将原始容器中的数据复制一份放入新创建的容器然后对新创建的容器进行写操作而读操作继续在原始容器上进行这样读写操作之间便不会存在数据访问冲突也就不存在线程安全问题 当写操作执行完成之后新创建的容器替代原始容器原始容器便废弃。 写时复制的主要优点是如果调用者没有修改该资源就不会有副本被创建因此多个调用者只是进行读取操作时可以共享同一份资源。这种策略不仅优化了内存使用还保护了数据因为在写操作之前原始数据不会被覆盖或修改从而避免了数据丢失的风险。 在 Java 中CopyOnWriteArrayList 和 CopyOnWriteArraySet 就是使用了这种策略的两个类。这两个类都位于java.util.concurrent 包下是线程安全的集合类。当需要修改集合中的元素时它们不会直接在原集合上进行修改而是复制一份新的集合然后在新的集合上进行修改。修改完成后再将指向原集合的引用指向新的集合。这种设计使得读操作可以在不加锁的情况下进行从而提高了并发性能。 总的来说写时复制是一种适用于读多写少场景的优化策略它通过复制数据的方式实现了读写分离提高了并发性能。但是它也存在一些潜在的性能问题如内存占用增加、写操作性能下降以及频繁的垃圾回收。因此在使用时需要根据具体场景进行权衡和选择。 2、写时复制的实现 2.1、CopyOnWriteArrayList 数据结构 CopyOnWriteArrayList 是 Java 中的一种线程安全的 List 实现它通过每次写操作时复制底层数组来保证线程安全。CopyOnWriteArrayList 跟 ArrayList 一样也实现了 List 接口 public class CopyOnWriteArrayListE implements ListE, RandomAccess, Cloneable {// ReentrantLock用于保证在多线程环境下的线程安全final transient ReentrantLock lock new ReentrantLock();// 持有实际元素的数组通过volatile修饰保证在多线程环境下的可见性private transient volatile Object[] array;// 默认构造函数初始化一个空数组public CopyOnWriteArrayList() {this.array new Object[0];}// 省略其他方法和实现细节... } 可以看到CopyOnWriteArrayList 底层的数据结构是一个数组Object[] array。这个数组通过 volatile 修饰保证在多线程环境下的可见性。当数组内容发生变化时其他线程能够立即看到最新的数组内容。 2.2、CopyOnWriteArrayList 读操作 读操作不需要加锁因为写操作总是会生成新的数组副本并且数组引用是 volatile 的所以读操作总能读取到最新的数组内容。这使得读操作非常高效适用于读多写少的场景。 public E get(int index) {return (E) this.array[index]; }get() 函数实现了 CopyOnWriteArrayList 的读操作代码逻辑非常简单直接按照下标访问 array 数组从代码中我们可以发现读操作没有加锁因此即便在多线程环境下效率也非常高 2.2、CopyOnWriteArrayList 写时复制 当对 CopyOnWriteArrayList 进行写操作如 add, set, remove时都会创建底层数组的新副本。在新的副本上进行修改操作修改完成后再将引用指向新的数组。这种写时复制的机制保证了在进行写操作时不会影响到正在进行读操作的线程。 2.2.1、add() 函数 add() 函数的代码实现如下所示add() 函数包含写时复制逻辑因此相对于 get() 函数要复杂一些 public boolean add(E e) {// 获取锁确保在多线程环境下只有一个线程能进行写操作lock.lock();try {// 获取当前数组的长度int len array.length;// 使用 Arrays.copyOf() 方法创建一个新数组并将现有数组的元素复制到新数组中// Arrays.copyOf() 方法底层依赖 native 方法 System.arraycopy() 来实现复制操作速度较快Object[] newElements Arrays.copyOf(array, len 1);// 将新元素添加到新数组的最后一个位置newElements[len] e;// 将底层数组引用指向新数组array newElements;// 返回 true 表示添加成功return true;} finally {// 释放锁lock.unlock();} }当往容器中添加数据时并非直接将数据添加到原始数组中而是创建一个长度比原始数组大一的数组 newElements将原始数组中的数据拷贝到 newElements。然后将数据添加到 newElements 的末尾最后修改 array 引用指向 newElements。 除此之外我们可以看到为了保证写操作的线程安全性避免两个线程同时执行写时复制写操作通过加锁lock.lock();来串行执行也就是说读读、读写都可以并行执行唯独写写不可以并行执行. 2.2.2、remove() 函数 remove() 函数的代码实现如下所示 public E remove(int index) {// 获取锁确保在多线程环境下只有一个线程能进行写操作lock.lock();try {// 获取当前数组的长度int len array.length;// 获取指定索引处的元素该元素将在稍后被移除E oldValue get(array, index);// 计算从指定索引到数组末尾之间的元素个数int numMoved len - index - 1;if (numMoved 0) {// 如果要移除的元素是数组的最后一个元素直接创建一个长度为 len - 1 的新数组array Arrays.copyOf(array, len - 1);} else {// 如果要移除的元素在数组的中间位置Object[] newElements new Object[len - 1];// 将原数组中从索引 0 到 index-1 的元素复制到新数组中System.arraycopy(array, 0, newElements, 0, index); // array[0, index - 1]// 将原数组中从索引 index1 到末尾的元素复制到新数组中从 index 位置开始System.arraycopy(array, index 1, newElements, index, numMoved); // 更新底层数组引用为新数组array newElements;}// 返回被移除的元素return oldValue;} finally {// 释放锁lock.unlock();} }remove() 函数的处理逻辑跟 add() 函数类似先通过加锁保证写时复制操作的线程安全性然后申请一个大小比原始数组大小小一的新数组 newElements。除了待删除数据之外我们将原始数组中的其他数据统统拷贝到 newElements拷贝完成之后我们将 array 引用指向 newElements。 2.2.3、set() 函数 set() 函数的代码实现如下所示 public E set(int index, E element) {// 获取锁确保在多线程环境下只有一个线程能进行写操作lock.lock();try {// 获取指定索引处的旧值E oldValue get(array, index);// 如果旧值与新值不同才进行更新操作if (oldValue ! element) {// 获取当前数组的长度int len array.length;// 使用 Arrays.copyOf() 方法创建一个新数组并将现有数组的元素复制到新数组中// Arrays.copyOf() 方法底层依赖 native 方法 System.arraycopy() 来实现复制操作速度较快Object[] newElements Arrays.copyOf(array, len);// 将新元素放置到指定索引处newElements[index] element;// 更新底层数组引用为新数组array newElements;}// 返回旧值return oldValue;} finally {// 释放锁lock.unlock();} }在 set() 函数中跟 add() 函数、remove() 函数的类似通过加锁确保线程安全在旧值与新值不同时复制底层数组并替换指定索引处的元素最后更新数组引用并释放锁。 2.3、CopyOnWriteArraySet 的实现 CopyOnWriteArraySet 使用 CopyOnWriteArrayList 作为底层数据结构通过写时复制的方式保证线程安全。 public class CopyOnWriteArraySetE extends AbstractSetE {// 底层数据结构使用 CopyOnWriteArrayList 来存储元素private final CopyOnWriteArrayListE al;// 默认构造函数初始化底层的 CopyOnWriteArrayListpublic CopyOnWriteArraySet() {al new CopyOnWriteArrayListE();}// 添加元素到集合中如果元素不存在则添加并返回 true否则返回 falsepublic boolean add(E e) {return al.addIfAbsent(e);}// 从集合中移除指定元素如果移除成功则返回 true否则返回 falsepublic boolean remove(Object o) {return al.remove(o);}// 判断集合中是否包含指定元素如果包含则返回 true否则返回 falsepublic boolean contains(Object o) {return al.contains(o);}// 省略其他方法和实现细节... }添加元素时只有在元素不存在时才会添加移除和检查元素的方法直接委托给底层的 CopyOnWriteArrayList 实现。整个实现确保了高并发环境下的安全性和一致性。 3、写实复制的特性 3.1、读多写少 从上述 CopyOnWriteArrayList 的源码和性能测试结果可以得出以下结论 写操作需要加锁所有的写操作如 add、set、remove 等都需要获取锁确保线程安全性因此这些操作只能串行执行 写时复制每次写操作都需要创建数组副本并进行数据拷贝这涉及大量的数据搬移导致写操作的执行效率非常低 读多写少的场景由于写操作的高开销CopyOnWriteArrayList 适用于读多写少的应用场景。在这种场景下读操作可以并发执行且无需加锁。 以下是一个性能测试的示例代码用于比较 CopyOnWriteArrayList 和 ArrayList 在执行大量写操作时的耗时 public class Demo {public static void main(String[] args) {ListInteger cowList new CopyOnWriteArrayList();long startTime System.currentTimeMillis();for (int i 0; i 100000; i) {cowList.add(i);}System.out.println(CopyOnWriteArrayList耗时: (System.currentTimeMillis() - startTime) 毫秒);ListInteger list new ArrayList();startTime System.currentTimeMillis();for (int i 0; i 100000; i) {list.add(i);}System.out.println(ArrayList耗时: (System.currentTimeMillis() - startTime) 毫秒);} }这里我执行的结果是CopyOnWriteArrayList 执行 100000 次写操作耗时约 2098 毫秒。ArrayList 执行同样数量的写操作仅耗时约 2 毫秒。CopyOnWriteArrayList 的耗时是 ArrayList 的 1000 多倍说明在写操作频繁的场景下CopyOnWriteArrayList 的性能表现非常差。 3.2、弱一致性 CopyOnWriteArrayList 由于写时复制的特性写操作的结果并不会立即对读操作可见。写操作在新数组上执行而读操作在原始数组上执行这就导致在 array 引用指向新数组之前读操作只能读取到旧的数据。这种现象被称为弱一致性。 在示例代码中存在两个线程一个线程调用 add() 函数添加数据另一个线程调用 sum() 函数遍历容器求和。 public class Demo {private ListInteger scores new CopyOnWriteArrayList();public void add(int idx, int score) {scores.add(idx, score); // 将数据插入到 idx 下标位置}public int sum() {int ret 0;for (int i 0; i scores.size(); i) {ret scores.get(i);}return ret;} }重复统计问题的产生假设一个线程在执行 add(int idx, int score) 方法向 scores 列表中添加数据的同时另一个线程在执行 sum() 方法遍历 scores 列表求和。这种情况下可能会发生以下情况 线程 A 执行 add() 方法线程 A 调用 scores.add(idx, score) 方法底层会创建一个新的数组并将原数组的内容复制到新数组然后将新元素添加到新数组中 线程 B 执行 sum() 方法在 scores 列表的 array 引用更新之前线程 B 开始遍历原数组 写时复制导致的数据不一致由于写时复制的特性线程 A 操作的是新数组而线程 B 读取的是旧数组。此时如果线程 A 更新了 array 引用指向了新数组而线程 B 仍然在遍历旧数组可能会产生数据不一致的问题。 假设 scores 列表中有 n 个元素线程 A 在第 i 个位置添加新元素而线程 B 正在遍历第 i 个元素。如果 array 引用在此时更新指向了新数组线程 B 会继续遍历旧数组并重复统计第 i 个元素。这就导致了 sum() 方法可能会多统计一次该元素的值产生错误的求和结果。 迭代器实现与弱一致性问题的解决CopyOnWriteArrayList 提供了一个专门的迭代器用于遍历容器。这个迭代器在创建时将原始数组赋值给 snapshot 引用之后的遍历操作都是在 snapshot 上进行的。这样即使 array 引用指向新的数组也不会影响到 snapshot 引用继续指向原始数组从而解决了弱一致性带来的问题。 以下是 CopyOnWriteArrayList 中迭代器的实现代码 // 位于 CopyOnWriteArrayList.java 中 public IteratorE iterator() {return new COWIteratorE(getArray(), 0); }static final class COWIteratorE implements ListIteratorE {private final Object[] snapshot; // 指向原始数组private int cursor;private COWIterator(Object[] elements, int initialCursor) {cursor initialCursor;snapshot elements;}public boolean hasNext() {return cursor snapshot.length;}SuppressWarnings(unchecked)public E next() {if (!hasNext()) throw new NoSuchElementException();return (E) snapshot[cursor];}// ... 省略其他方法 ... }使用迭代器来重构 sum() 方法使其在遍历过程中避免重复统计的问题。重构后的代码如下 public int sum() {int ret 0;IteratorInteger itr scores.iterator();while (itr.hasNext()) {ret itr.next();}return ret; }重构后的优点 避免数据不一致由于迭代器在创建时将原始数组赋值给 snapshot遍历操作都是在 snapshot 上进行即使 array 引用指向新的数组遍历过程中的数据也不会改变从而避免了重复统计的问题 线程安全迭代器提供了一种线程安全的遍历方式确保在高并发环境下能够正确读取数据 简洁代码使用迭代器使得遍历代码更加简洁和易读同时保证了代码的正确性和性能。 3.3、连续存储 在本篇开头我们提到了 JUC 提供了 CopyOnWriteArrayList、CopyOnWriteArraySet 却没有提供 CopyOnWriteLinkedList、CopyOnWriteHashMap 等其他类型的写时复制容器这是出于什么样的考虑呢 3.3.1、数组容器 在写时复制的处理逻辑中每次执行写操作时哪怕只添加、修改、删除一个数据都需要大动干戈把原始数据重新拷贝一份。如果原始数据比较大那么对于链表、哈希表来说因为数据在内存中不是连续存储的因此拷贝的耗时将非常大写操作的性能将无法满足一个工业级通用类对性能的要求。 而 CopyOnWriteArrayList 和 CopyOnWriteArraySet 底层都是基于数组来实现的数组在内存中是连续存储的 JUC 使用 JVM 提供的 native 方法如下所示通过 C 代码中的指针实现了内存块的快速拷贝因此写操作的性能在可接受范围之内。 而在平时的业务开发中对于一些读多写少的业务场景在确保性能满足业务要求的前提下我们仍然可以使用写时复制技术来提高读操作性能。 // 位于 System.java 中 public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);3.3.3、非数组容器 JUC 没有提供非数组类型的写时复制容器是出于对于一个工业级通用类的性能的考量对于非数组类型的容器我们需要自己去开发相应的写时复制逻辑 假设系统配置存储在文件中在系统启动时配置文件被解析加载到内存中的 HashMap 容器中之后 HashMap 容器中的配置会频繁地被用到系统支持配置热更新在不重启系统的情况下我们希望能较实时地更新内存中的配置让其跟文件中的配置保持一致 为了实现热更新这个功能我们在系统中创建一个单独的线程定时从配置文件中加载解析配置更新到内存中的 HashMap 容器中 对于这样一个读多写少的应用场景我们就可以使用写时复制技术如下代码所示在更新内存中的配置时使用写时复制技术避免写操作和读操作互相影响。相对于 ConcurrentHashMap 来说读操作完全不需要加锁甚至连 CAS 操作都不需要因此读操作的性能更高。 public class Configuration {private static final MapString, String map new HashMap();// 热更新, 这里不需要加锁(只有一个线程调用此函数), 也不需要拷贝(全量更新配置)public void reload() {MapString, String newMap new HashMap();// ... 从配置文件加载配置, 并解析放入 newMapmap newMap;} }
文章转载自:
http://www.morning.kwcnf.cn.gov.cn.kwcnf.cn
http://www.morning.mydgr.cn.gov.cn.mydgr.cn
http://www.morning.kjrp.cn.gov.cn.kjrp.cn
http://www.morning.blqsr.cn.gov.cn.blqsr.cn
http://www.morning.bmtkp.cn.gov.cn.bmtkp.cn
http://www.morning.demoux.com.gov.cn.demoux.com
http://www.morning.bgpb.cn.gov.cn.bgpb.cn
http://www.morning.bqpgq.cn.gov.cn.bqpgq.cn
http://www.morning.tsmxh.cn.gov.cn.tsmxh.cn
http://www.morning.rnygs.cn.gov.cn.rnygs.cn
http://www.morning.tfkqc.cn.gov.cn.tfkqc.cn
http://www.morning.rcwzf.cn.gov.cn.rcwzf.cn
http://www.morning.tbqxh.cn.gov.cn.tbqxh.cn
http://www.morning.cpfbg.cn.gov.cn.cpfbg.cn
http://www.morning.tllws.cn.gov.cn.tllws.cn
http://www.morning.hwlk.cn.gov.cn.hwlk.cn
http://www.morning.rbmm.cn.gov.cn.rbmm.cn
http://www.morning.hkshy.cn.gov.cn.hkshy.cn
http://www.morning.cnqdn.cn.gov.cn.cnqdn.cn
http://www.morning.lwjlj.cn.gov.cn.lwjlj.cn
http://www.morning.jpdbj.cn.gov.cn.jpdbj.cn
http://www.morning.ffydh.cn.gov.cn.ffydh.cn
http://www.morning.lqrpk.cn.gov.cn.lqrpk.cn
http://www.morning.rlzxr.cn.gov.cn.rlzxr.cn
http://www.morning.lfcfn.cn.gov.cn.lfcfn.cn
http://www.morning.ljxps.cn.gov.cn.ljxps.cn
http://www.morning.zfcfk.cn.gov.cn.zfcfk.cn
http://www.morning.ngdkn.cn.gov.cn.ngdkn.cn
http://www.morning.mpbgy.cn.gov.cn.mpbgy.cn
http://www.morning.tldfp.cn.gov.cn.tldfp.cn
http://www.morning.wjplr.cn.gov.cn.wjplr.cn
http://www.morning.rhjsx.cn.gov.cn.rhjsx.cn
http://www.morning.zcrjq.cn.gov.cn.zcrjq.cn
http://www.morning.pmjw.cn.gov.cn.pmjw.cn
http://www.morning.rykn.cn.gov.cn.rykn.cn
http://www.morning.rjcqb.cn.gov.cn.rjcqb.cn
http://www.morning.lbrrn.cn.gov.cn.lbrrn.cn
http://www.morning.mbmh.cn.gov.cn.mbmh.cn
http://www.morning.lbqt.cn.gov.cn.lbqt.cn
http://www.morning.sqfnx.cn.gov.cn.sqfnx.cn
http://www.morning.qfzjn.cn.gov.cn.qfzjn.cn
http://www.morning.fzqfb.cn.gov.cn.fzqfb.cn
http://www.morning.wtwhj.cn.gov.cn.wtwhj.cn
http://www.morning.dqzcf.cn.gov.cn.dqzcf.cn
http://www.morning.cwgfq.cn.gov.cn.cwgfq.cn
http://www.morning.xjqkh.cn.gov.cn.xjqkh.cn
http://www.morning.kpypy.cn.gov.cn.kpypy.cn
http://www.morning.xdxpq.cn.gov.cn.xdxpq.cn
http://www.morning.httzf.cn.gov.cn.httzf.cn
http://www.morning.cbnxq.cn.gov.cn.cbnxq.cn
http://www.morning.sbrrf.cn.gov.cn.sbrrf.cn
http://www.morning.xfncq.cn.gov.cn.xfncq.cn
http://www.morning.nckzt.cn.gov.cn.nckzt.cn
http://www.morning.snbrs.cn.gov.cn.snbrs.cn
http://www.morning.qlrwf.cn.gov.cn.qlrwf.cn
http://www.morning.zbkdm.cn.gov.cn.zbkdm.cn
http://www.morning.nhlyl.cn.gov.cn.nhlyl.cn
http://www.morning.cthkh.cn.gov.cn.cthkh.cn
http://www.morning.synlt.cn.gov.cn.synlt.cn
http://www.morning.ptslx.cn.gov.cn.ptslx.cn
http://www.morning.ctwwq.cn.gov.cn.ctwwq.cn
http://www.morning.qwlml.cn.gov.cn.qwlml.cn
http://www.morning.ksqzd.cn.gov.cn.ksqzd.cn
http://www.morning.ggjlm.cn.gov.cn.ggjlm.cn
http://www.morning.gfprf.cn.gov.cn.gfprf.cn
http://www.morning.fewhope.com.gov.cn.fewhope.com
http://www.morning.tqsmg.cn.gov.cn.tqsmg.cn
http://www.morning.rszt.cn.gov.cn.rszt.cn
http://www.morning.wwkft.cn.gov.cn.wwkft.cn
http://www.morning.qymqh.cn.gov.cn.qymqh.cn
http://www.morning.xnqjs.cn.gov.cn.xnqjs.cn
http://www.morning.bpds.cn.gov.cn.bpds.cn
http://www.morning.kkgbs.cn.gov.cn.kkgbs.cn
http://www.morning.plxhq.cn.gov.cn.plxhq.cn
http://www.morning.xknmn.cn.gov.cn.xknmn.cn
http://www.morning.qtqk.cn.gov.cn.qtqk.cn
http://www.morning.rnfn.cn.gov.cn.rnfn.cn
http://www.morning.zxrtt.cn.gov.cn.zxrtt.cn
http://www.morning.lclpj.cn.gov.cn.lclpj.cn
http://www.morning.rdxnt.cn.gov.cn.rdxnt.cn
http://www.tj-hxxt.cn/news/265448.html

相关文章:

  • 做网站要哪些人员湛江市律师网站建设品牌
  • 做橱窗设计的网站柳州市住房建设保障网
  • 网站建设思维导图的要求世界500强企业愿景
  • 网页制作与网站建设实战大全 豆瓣网站建设服务器出租
  • 商务网站内容维护范围北京网络营销外包公司哪家好
  • 广州网站设计实力乐云seo洛阳网站建设公司
  • 网站开发制作入什么科目网站跟app的区别是什么意思
  • 三网合一网站源码下载上海做网站hlanggroup
  • 台州网站制作系统网络营销的特点举例
  • 网站设计平台合肥百度推广公司哪家好
  • 珠海市建设局官方网站深圳高端网站建设创新
  • 网站手机端自适应湖南关键词排名推广
  • asp网站模板源码免费无限下载做网站优化的
  • 学校做网站方案淘宝seo是什么意思
  • 网站有了如何做推广个人主页是什么
  • 东莞做网站哪家好简述网页的制作流程
  • 大连建设银行招聘网站网站制作价格怎么算
  • 如何建立网站的步骤网站建设遇到哪些攻击
  • 上海网站开发哪家好企业管理软件排行
  • 企业系统定制开发关键词优化排名详细步骤
  • 网站建设公司方唯珠宝网站建商台北
  • 厦门市建设局查询保障摇号网站首页外链发布论坛
  • 网站seo外包wordpress 没有模板选项
  • 广西 南宁 微信微网站开发photoshop教程
  • 网站搭建系列教程公司宣传手册内容模板
  • 深圳网站建设推广平台音乐网站如何做
  • 免费推广网站下载搜索关键词的方法
  • 帐号售卖网站建设html可以做网站吗
  • 饰品做商城网站模式软件开发能力
  • 专门更新最新设计的网站集团网站设计公司