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

江西建设部网站泉州seo网络优化公司

江西建设部网站,泉州seo网络优化公司,建设公司网站有什么好处,湘潭响应式网站建设 磐石网络目录 原子操作 定义 术语 处理器如何实现原子操作 处理器自动保证基本内存操作的原子性 使用总线锁保证原子性 使用缓存锁保证原子性 Java当中如何实现原子操作 Atomic 定义 原子更新基本类型类 原子更新数组类 原子更新引用类型 原子更新字段类 Unsafe应用解析…目录 原子操作 定义 术语 处理器如何实现原子操作 处理器自动保证基本内存操作的原子性 使用总线锁保证原子性 使用缓存锁保证原子性 Java当中如何实现原子操作 Atomic 定义 原子更新基本类型类 原子更新数组类 原子更新引用类型 原子更新字段类 Unsafe应用解析 如何获取Unsafe实例 Unsafe功能介绍 内存操作  使用堆外内存的原因 典型应用 CAS相关  典型应用 线程调度  典型应用 内存屏障 典型应用 原子操作 定义 原子atom本意是“不能被进一步分割的最小粒子”而原子操作atomic operation意为”不可被中断的一个或一系列操作” 。在多处理器上实现原子操作就变得有点复杂。本文让我们一起来聊一聊在Inter处理器和Java里是如何实现原子操作的。 术语 术语名称 英文 解释 缓存行 Cache line 缓存的最小操作单位 比较并交换 Compare and Swap CAS操作需要输入两个数值一个旧值期望操作前的值和一个新值在操作期间先比较下在旧值有没有发生变化如果没有发生变化才交换成新值发生了变化则不交换。 CPU流水线 CPU pipeline CPU流水线的工作方式就象工业生产上的装配流水线在CPU中由5~6个不同功能的电路单元组成一条指令处理流水线然后将一条X86指令分成5~6步后再由这些电路单元分别执行这样就能实现在一个CPU时钟周期完成一条指令因此提高CPU的运算速度。 内存顺序冲突 Memory order violation 内存顺序冲突一般是由假共享引起假共享是指多个CPU同时修改同一个缓存行的不同部分而引起其中一个CPU的操作无效当出现这个内存顺序冲突时CPU必须清空流水线。 处理器如何实现原子操作 32位IA-32处理器使用基于对缓存加锁或总线加锁的方式来实现多处理器之间的原子操作。 处理器自动保证基本内存操作的原子性 首先处理器会自动保证基本的内存操作的原子性。处理器保证从系统内存当中读取或者写入一个字节是原子的意思是当一个处理器读取一个字节时其他处理器不能访问这个字节的内存地址。奔腾6和最新的处理器能自动保证单处理器对同一个缓存行里进行16/32/64位的操作是原子的但是复杂的内存操作处理器不能自动保证其原子性比如跨总线宽度跨多个缓存行跨页表的访问。但是处理器提供总线锁定和缓存锁定两个机制来保证复杂内存操作的原子性。 使用总线锁保证原子性 第一个机制是通过总线锁保证原子性。如果多个处理器同时对共享变量进行读改写i就是经典的读改写操作操作那么共享变量就会被多个处理器同时进行操作这样读改写操作就不是原子的操作完之后共享变量的值会和期望的不一致举个例子如果i1,我们进行两次i操作我们期望的结果是3但是有可能结果是2。如下图 原因是有可能多个处理器同时从各自的缓存中读取变量i分别进行加一操作然后分别写入系统内存当中。那么想要保证读改写共享变量的操作是原子的就必须保证CPU1读改写共享变量的时候CPU2不能操作缓存了该共享变量内存地址的缓存。  处理器使用总线锁就是来解决这个问题的。所谓总线锁就是使用处理器提供的一个LOCK信号当一个处理器在总线上输出此信号时其他处理器的请求将被阻塞住,那么该处理器可以独占使用共享内存。 使用缓存锁保证原子性 第二个机制是通过缓存锁定保证原子性。在同一时刻我们只需保证对某个内存地址的操作是原子性即可但总线锁定把CPU和内存之间通信锁住了这使得锁定期间其他处理器不能操作其他内存地址的数据所以总线锁定的开销比较大最近的处理器在某些场合下使用缓存锁定代替总线锁定来进行优化。 频繁使用的内存会缓存在处理器的L1L2和L3高速缓存里那么原子操作就可以直接在处理器内部缓存中进行并不需要声明总线锁在奔腾6和最近的处理器中可以使用“缓存锁定”的方式来实现复杂的原子性。所谓“缓存锁定”就是如果缓存在处理器缓存行中内存区域在LOCK操作期间被锁定当它执行锁操作回写内存时处理器不在总线上声言LOCK信号而是修改内部的内存地址并允许它的缓存一致性机制来保证操作的原子性因为缓存一致性机制会阻止同时修改被两个以上处理器缓存的内存区域数据当其他处理器回写已被锁定的缓存行的数据时会起缓存行无效在例1中当CPU1修改缓存行中的i时使用缓存锁定那么CPU2就不能同时缓存了i的缓存行。 但是有两种情况下处理器不会使用缓存锁定。第一种情况是当操作的数据不能被缓存在处理器内部或操作的数据跨多个缓存行cache line则处理器会调用总线锁定。第二种情况是有些处理器不支持缓存锁定。对于Inter486和奔腾处理器,就算锁定的内存区域在处理器的缓存行中也会调用总线锁定。 以上两个机制我们可以通过Inter处理器提供了很多LOCK前缀的指令来实现。比如位测试和修改指令BTSBTRBTC交换指令XADDCMPXCHG和其他一些操作数和逻辑指令比如ADD加OR或等被这些指令操作的内存区域就会加锁导致其他处理器不能同时访问它。 我就是感觉总线锁就是锁的所有主内存中缓存行的数据而缓存锁只是针对一个缓存行进行加锁操作 Java当中如何实现原子操作 在java中可以通过锁和循环CAS的方式来实现原子操作。 JVM中的CAS操作正是利用了上文中提到的处理器提供的CMPXCHG指令实现的。自旋CAS实现的基本思路就是循环进行CAS操作直到成功为止具体的类可以参见juc下的atomic包内的原子类。 Atomic 定义 在Atomic包里一共有12个类四种原子更新方式分别是原子更新基本类型原子更新数组原子更新引用和原子更新字段。Atomic包里的类基本都是使用Unsafe实现的包装类。 基本类AtomicInteger、AtomicLong、AtomicBoolean 引用类型AtomicReference、AtomicReference的ABA实例、AtomicStampedRerence、AtomicMarkableReference 数组类型AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray 属性原子修改器UpdaterAtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater 原子更新基本类型类 用于通过原子的方式更新基本类型Atomic包提供了以下三个类 AtomicBoolean原子更新布尔类型。AtomicInteger原子更新整型。AtomicLong原子更新长整型。 AtomicInteger的常用方法如下 int addAndGet(int delta) 以原子方式将输入的数值与实例中的值AtomicInteger里的value相加并返回结果boolean compareAndSet(int expect, int update) 如果输入的数值等于预期值则以原子方式将该值设置为输入的值。int getAndIncrement()以原子方式将当前值加1注意这里返回的是自增前的值。void lazySet(int newValue)最终会设置成newValue使用lazySet设置值后可能导致其他线程在之后的一小段时间内还是可以读到旧的值。int getAndSet(int newValue)以原子方式设置为newValue的值并返回旧值。 Atomic包提供了三种基本类型的原子更新但是Java的基本类型里还有charfloat和double等。那么问题来了如何原子的更新其他的基本类型呢Atomic包里的类基本都是使用Unsafe实现的Unsafe只提供了三种CAS方法compareAndSwapObjectcompareAndSwapInt和compareAndSwapLong再看AtomicBoolean源码发现其是先把Boolean转换成整型再使用compareAndSwapInt进行CAS所以原子更新double也可以用类似的思路来实现。 原子更新数组类 通过原子的方式更新数组里的某个元素Atomic包提供了以下三个类 AtomicIntegerArray原子更新整型数组里的元素。AtomicLongArray原子更新长整型数组里的元素。AtomicReferenceArray原子更新引用类型数组里的元素。 AtomicIntegerArray类主要是提供原子的方式更新数组里的整型其常用方法如下 int addAndGet(int i, int delta)以原子方式将输入值与数组中索引i的元素相加。boolean compareAndSet(int i, int expect, int update)如果当前值等于预期值则以原子方式将数组位置i的元素设置成update值。 原子更新引用类型 原子更新基本类型的AtomicInteger只能更新一个变量如果要原子的更新多个变量就需要使用这个原子更新引用类型提供的类。Atomic包提供了以下三个类 AtomicReference原子更新引用类型。AtomicReferenceFieldUpdater原子更新引用类型里的字段。AtomicMarkableReference原子更新带有标记位的引用类型。可以原子的更新一个布尔类型的标记位和引用类型。构造方法是AtomicMarkableReference(V initialRef, boolean initialMark) 原子更新字段类 如果我们只需要某个类里的某个字段那么就需要使用原子更新字段类Atomic包提供了以下三个类 AtomicIntegerFieldUpdater原子更新整型的字段的更新器。AtomicLongFieldUpdater原子更新长整型字段的更新器。AtomicStampedReference原子更新带有版本号的引用类型。该类将整数值与引用关联起来可用于原子的更数据和数据的版本号可以解决使用CAS进行原子更新时可能出现的ABA问题。 原子更新字段类都是抽象类每次使用都时候必须使用静态方法newUpdater创建一个更新器。原子更新类的字段的必须使用public volatile修饰符。 Unsafe应用解析 Unsafe是位于sun.misc包下的一个类主要提供一些用于执行低级别、不安全操作的方法如直接访问系统内存资源、自主管理内存资源等这些方法在提升Java运行效率、增强Java语言底层资源操作能力方面起到了很大的作用。但由于Unsafe类使Java语言拥有了类似C语言指针一样操作内存空间的能力这无疑也增加了程序发生相关指针问题的风险。在程序中过度、不正确使用Unsafe类会使得程序出错的概率变大使得Java这种安全的语言变得不再“安全”因此对Unsafe的使用一定要慎重。 Unsafe类为一单例实现提供静态方法getUnsafe获取Unsafe实例当且仅当调用getUnsafe方法的类为引导类加载器所加载时才合法否则抛出SecurityException异常。 public class Unsafe {// 单例对象private static final Unsafe theUnsafe;private Unsafe() {}CallerSensitivepublic static Unsafe getUnsafe() {Class var0 Reflection.getCallerClass();// 仅在引导类加载器BootstrapClassLoader加载时才合法if(!VM.isSystemDomainLoader(var0.getClassLoader())) {throw new SecurityException(Unsafe);} else {return theUnsafe;}} } 如何获取Unsafe实例 1、从getUnsafe方法的使用限制条件出发通过Java命令行命令-Xbootclasspath/a把调用Unsafe相关方法的类A所在jar包路径追加到默认的bootstrap路径中使得A被引导类加载器加载从而通过Unsafe.getUnsafe方法安全的获取Unsafe实例。 java -Xbootclasspath/a:${path} // 其中path为调用Unsafe相关方法的类所在jar包路径 2、通过反射获取单例对象theUnsafe。 public class UnsafeInstance {public static Unsafe reflectGetUnsafe() {try {Field field Unsafe.class.getDeclaredField(theUnsafe);field.setAccessible(true);return (Unsafe) field.get(null);} catch (Exception e) {e.printStackTrace();}return null;} } Unsafe功能介绍 Unsafe提供的API大致可分为内存操作、CAS、Class相关、对象操作、线程调度、系统信息获取、内存屏障、数组操作等几类下面将对其相关方法和应用场景进行详细介绍。 内存操作  这部分主要包含堆外内存的分配、拷贝、释放、给定地址值操作等方法。 //分配内存, 相当于C的malloc函数 public native long allocateMemory(long bytes); //扩充内存 public native long reallocateMemory(long address, long bytes); //释放内存 public native void freeMemory(long address); //在给定的内存块中设置值 public native void setMemory(Object o, long offset, long bytes, byte value); //内存拷贝 public native void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes); //获取给定地址值忽略修饰限定符的访问限制。与此类似操作还有: getIntgetDoublegetLonggetChar等 public native Object getObject(Object o, long offset); //为给定地址设置值忽略修饰限定符的访问限制与此类似操作还有: putInt,putDoubleputLongputChar等 public native void putObject(Object o, long offset, Object x); public native byte getByte(long address); //为给定地址设置byte类型的值当且仅当该内存地址为allocateMemory分配 时此方法结果才是确定的 public native void putByte(long address, byte x); 通常我们在Java中创建的对象都处于堆内内存heap中堆内内存是由JVM所管控的Java进程内存并且它们遵循JVM的内存管理机制JVM会采用垃圾回收机制统一管理堆内存。与之相对的是堆外内存存在于JVM管控之外的内存区域Java中对堆外内存的操作依赖于Unsafe提供的操作堆外内存的native方法。 使用堆外内存的原因 对垃圾回收停顿的改善。由于堆外内存是直接受操作系统管理而不是JVM所以当我们使用堆外内存时即可保持较小的堆内内存规模。从而在GC时减少回收停顿对于应用的影响。提升程序I/O操作的性能。通常在I/O通信过程中会存在堆内内存到堆外内存的数据拷贝操作对于需要频繁进行内存间数据拷贝且生命周期较短的暂存数据都建议存储到堆外内存。 典型应用 DirectByteBuffer是Java用于实现堆外内存的一个重要类通常用在通信过程中做缓冲池如在Netty、MINA等NIO框架中应用广泛。DirectByteBuffer对于堆外内存的创建、使用、销毁等逻辑均由Unsafe提供的堆外内存API来实现。 下图为DirectByteBuffer构造函数创建DirectByteBuffer的时候通过Unsafe.allocateMemory分配内存、Unsafe.setMemory进行内存初始化而后构建Cleaner对象用于跟踪DirectByteBuffer对象的垃圾回收以实现当DirectByteBuffer被垃圾回收时分配的堆外内存一起被释放。 CAS相关  如下源代码释义所示这部分主要为CAS相关操作的方法。 /*** CAS* param o 包含要修改field的对象* param offset 对象中某field的偏移量* param expected 期望值* param update 更新值* return true | false*/ public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);典型应用 如下图所示AtomicInteger的实现中静态字段valueOffset即为字段value的内存偏移地址valueOffset的值在AtomicInteger初始化时在静态代码块中通过Unsafe的objectFieldOffset方法获取。在AtomicInteger中提供的线程安全方法中通过字段valueOffset的值可以定位到AtomicInteger对象中value的内存地址从而可以根据CAS实现对value字段的原子操作。 下图为某个AtomicInteger对象自增操作前后的内存示意图对象的基地址baseAddress“0x110000”通过baseAddressvalueOffset得到value的内存地址valueAddress“0x11000c”然后通过CAS进行原子性的更新操作成功则返回否则继续重试直到更新成功为止。  线程调度  包括线程挂起、恢复、锁机制等方法。 /取消阻塞线程 public native void unpark(Object thread); //阻塞线程 public native void park(boolean isAbsolute, long time); //获得对象锁可重入锁 Deprecated public native void monitorEnter(Object o); //释放对象锁 Deprecated public native void monitorExit(Object o); //尝试获取对象锁 Deprecated public native boolean tryMonitorEnter(Object o); 方法park、unpark即可实现线程的挂起与恢复将一个线程进行挂起是通过park方法实现的调用park方法后线程将一直阻塞直到超时或者中断等条件出现unpark可以终止一个挂起的线程使其恢复正常。 典型应用 Java锁和同步器框架的核心类AbstractQueuedSynchronizer就是通过调用LockSupport.park()和LockSupport.unpark()实现线程的阻塞和唤醒的而LockSupport的park、unpark方法实际是调用Unsafe的park、unpark方式来实现。 内存屏障 在Java 8中引入用于定义内存屏障也称内存栅栏内存栅障屏障指令等是一类同步屏障指令是CPU或编译器在对内存随机访问的操作中的一个同步点使得此点之前的所有读写操作都执行后才可以开始执行此点之后的操作避免代码重排序。 //内存屏障禁止load操作重排序。屏障前的load操作不能被重排序到屏障后屏障后的load操作不能被重排序到屏障前 public native void loadFence(); //内存屏障禁止store操作重排序。屏障前的store操作不能被重排序到屏障后屏障后的store操作不能被重排序到屏障前 public native void storeFence(); //内存屏障禁止load、store操作重排序 public native void fullFence(); 典型应用 在Java 8中引入了一种锁的新机制——StampedLock它可以看成是读写锁的一个改进版本。StampedLock提供了一种乐观读锁的实现这种乐观读锁类似于无锁的操作完全不会阻塞写线程获取写锁从而缓解读多写少时写线程“饥饿”现象。由于StampedLock提供的乐观读锁不阻塞写线程获取读锁当线程共享变量从主内存load到线程工作内存时会存在数据不一致问题所以当使用StampedLock的乐观读锁时需要遵从如下图用例中使用的模式来确保数据的一致性。 如上图用例所示计算坐标点Point对象包含点移动方法move及计算此点到原点的距离的方法distanceFromOrigin。在方法distanceFromOrigin中首先通过tryOptimisticRead方法获取乐观读标记然后从主内存中加载点的坐标值 (x,y)而后通过StampedLock的validate方法校验锁状态判断坐标点(x,y)从主内存加载到线程工作内存过程中主内存的值是否已被其他线程通过move方法修改如果validate返回值为true证明(x, y)的值未被修改可参与后续计算否则需加悲观读锁再次从主内存加载(x,y)的最新值然后再进行距离计算。其中校验锁状态这步操作至关重要需要判断锁状态是否发生改变从而判断之前copy到线程工作内存中的值是否与主内存的值存在不一致。 下图为StampedLock.validate方法的源码实现通过锁标记与相关常量进行位运算、比较来校验锁状态在校验逻辑之前会通过Unsafe的loadFence方法加入一个load内存屏障目的是避免上图用例中步骤②和StampedLock.validate中锁状态校验运算发生重排序导致锁状态校验不准确的问题。
文章转载自:
http://www.morning.qyglt.cn.gov.cn.qyglt.cn
http://www.morning.bnpcq.cn.gov.cn.bnpcq.cn
http://www.morning.pmsl.cn.gov.cn.pmsl.cn
http://www.morning.nkqxb.cn.gov.cn.nkqxb.cn
http://www.morning.jgykx.cn.gov.cn.jgykx.cn
http://www.morning.gmgnp.cn.gov.cn.gmgnp.cn
http://www.morning.lwtfr.cn.gov.cn.lwtfr.cn
http://www.morning.gycyt.cn.gov.cn.gycyt.cn
http://www.morning.rlwgn.cn.gov.cn.rlwgn.cn
http://www.morning.xgchm.cn.gov.cn.xgchm.cn
http://www.morning.trhlb.cn.gov.cn.trhlb.cn
http://www.morning.kbgzj.cn.gov.cn.kbgzj.cn
http://www.morning.tqdqc.cn.gov.cn.tqdqc.cn
http://www.morning.eviap.com.gov.cn.eviap.com
http://www.morning.zwdrz.cn.gov.cn.zwdrz.cn
http://www.morning.nqxdg.cn.gov.cn.nqxdg.cn
http://www.morning.rwlnk.cn.gov.cn.rwlnk.cn
http://www.morning.kcdts.cn.gov.cn.kcdts.cn
http://www.morning.rfbpq.cn.gov.cn.rfbpq.cn
http://www.morning.lmfxq.cn.gov.cn.lmfxq.cn
http://www.morning.bnjnp.cn.gov.cn.bnjnp.cn
http://www.morning.thzwj.cn.gov.cn.thzwj.cn
http://www.morning.bnygf.cn.gov.cn.bnygf.cn
http://www.morning.zqnmp.cn.gov.cn.zqnmp.cn
http://www.morning.cqrenli.com.gov.cn.cqrenli.com
http://www.morning.cjqqj.cn.gov.cn.cjqqj.cn
http://www.morning.yprjy.cn.gov.cn.yprjy.cn
http://www.morning.pxwjp.cn.gov.cn.pxwjp.cn
http://www.morning.bzwxr.cn.gov.cn.bzwxr.cn
http://www.morning.pghry.cn.gov.cn.pghry.cn
http://www.morning.lmhwm.cn.gov.cn.lmhwm.cn
http://www.morning.fqssx.cn.gov.cn.fqssx.cn
http://www.morning.fxwkl.cn.gov.cn.fxwkl.cn
http://www.morning.gfqjf.cn.gov.cn.gfqjf.cn
http://www.morning.cbchz.cn.gov.cn.cbchz.cn
http://www.morning.wjzzh.cn.gov.cn.wjzzh.cn
http://www.morning.jglqn.cn.gov.cn.jglqn.cn
http://www.morning.frtt.cn.gov.cn.frtt.cn
http://www.morning.nqdkx.cn.gov.cn.nqdkx.cn
http://www.morning.dtmjn.cn.gov.cn.dtmjn.cn
http://www.morning.dzzjq.cn.gov.cn.dzzjq.cn
http://www.morning.hqrkq.cn.gov.cn.hqrkq.cn
http://www.morning.mtbsd.cn.gov.cn.mtbsd.cn
http://www.morning.rbjf.cn.gov.cn.rbjf.cn
http://www.morning.tqpds.cn.gov.cn.tqpds.cn
http://www.morning.prmyx.cn.gov.cn.prmyx.cn
http://www.morning.xzjsb.cn.gov.cn.xzjsb.cn
http://www.morning.yrngx.cn.gov.cn.yrngx.cn
http://www.morning.phxns.cn.gov.cn.phxns.cn
http://www.morning.fsnhz.cn.gov.cn.fsnhz.cn
http://www.morning.wqfj.cn.gov.cn.wqfj.cn
http://www.morning.lbggk.cn.gov.cn.lbggk.cn
http://www.morning.hbdqf.cn.gov.cn.hbdqf.cn
http://www.morning.zkbxx.cn.gov.cn.zkbxx.cn
http://www.morning.rgyts.cn.gov.cn.rgyts.cn
http://www.morning.gtqws.cn.gov.cn.gtqws.cn
http://www.morning.bpttm.cn.gov.cn.bpttm.cn
http://www.morning.zjqwr.cn.gov.cn.zjqwr.cn
http://www.morning.rqnhf.cn.gov.cn.rqnhf.cn
http://www.morning.glxdk.cn.gov.cn.glxdk.cn
http://www.morning.zwzlf.cn.gov.cn.zwzlf.cn
http://www.morning.mrcpy.cn.gov.cn.mrcpy.cn
http://www.morning.qnzld.cn.gov.cn.qnzld.cn
http://www.morning.ysnbq.cn.gov.cn.ysnbq.cn
http://www.morning.pphgl.cn.gov.cn.pphgl.cn
http://www.morning.baohum.com.gov.cn.baohum.com
http://www.morning.krzrg.cn.gov.cn.krzrg.cn
http://www.morning.mnclk.cn.gov.cn.mnclk.cn
http://www.morning.btpzn.cn.gov.cn.btpzn.cn
http://www.morning.yqgny.cn.gov.cn.yqgny.cn
http://www.morning.tnrdz.cn.gov.cn.tnrdz.cn
http://www.morning.nqlnd.cn.gov.cn.nqlnd.cn
http://www.morning.gwqkk.cn.gov.cn.gwqkk.cn
http://www.morning.mnygn.cn.gov.cn.mnygn.cn
http://www.morning.nzkc.cn.gov.cn.nzkc.cn
http://www.morning.tknqr.cn.gov.cn.tknqr.cn
http://www.morning.nfmtl.cn.gov.cn.nfmtl.cn
http://www.morning.byywt.cn.gov.cn.byywt.cn
http://www.morning.hxrfb.cn.gov.cn.hxrfb.cn
http://www.morning.qqklk.cn.gov.cn.qqklk.cn
http://www.tj-hxxt.cn/news/246257.html

相关文章:

  • 做围棋题网站如何开发一个软件平台
  • 电脑课做网站的作业怎么打开自己做的网站
  • 企业网站建设项目实践报告旅游景点网站建设
  • illustrator 学习网站公司官网推广
  • 响应式设计网站案例全国猎头公司前十名
  • 企业网站建设合同怎样做一元购网站
  • 上海网站建设电色盲能治好吗
  • 所有爱做网站wordpress投稿页面路径怎么写
  • 怎样建立微网站直播app在线看片有哪些
  • skype在网站上怎么做链接32岁学做网站
  • 怀化网站优化加徽信xiala5效果好做网站常规语言
  • 公司建设网站流程钓鱼网站后台是怎么做的
  • 网站前端是做网站吗wordpress 多站点 主站点
  • 注册公司网站的步骤前端开发招聘信息
  • 营销型网站建设教程视频教程中国最大的免费素材网站
  • 2008 做网站大庆门户网站
  • 文本分析网站让wordpress自检
  • 移动网站建设平台html电影网站源码
  • 用PS怎么做网站界面泸县建设局网站
  • 上海亿网站建设长沙网站制作哪家强
  • 北京网站设计外包公司网站交易模块怎么做
  • 哈尔滨网站设计有哪些步骤wordpress主体公园
  • 梭子手做鱼网站深圳专业做网站专业公司
  • 接工程网站深圳彩页设计
  • 长沙网站制作教程自媒体平台注册官网下载
  • 东莞网站设计效果阿里巴巴logo发展史
  • 凡科网站建设步骤简单的网页制作素材
  • 关于计算机网站建设的论文灌南县建设局网站
  • 品牌网站定制动易网站 价格
  • 如何建设与维护网站如何用asp做视频网站