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

合肥做网站工作室个人网站建立多少钱

合肥做网站工作室,个人网站建立多少钱,永久免费国外ip代理,网络营销推广免费一、基本概念 1.什么是线程#xff1f; 线程就是#xff0c;操作系统能够进行运算调度的最小单位。它被包含在进程之中#xff0c;是进程中的实际运作单位。简单理解就是#xff1a;应用软件中互相独立#xff0c;可以同时运行的功能 2.什么是多线程#xff1f; 有了多线…一、基本概念 1.什么是线程 线程就是操作系统能够进行运算调度的最小单位。它被包含在进程之中是进程中的实际运作单位。简单理解就是应用软件中互相独立可以同时运行的功能 2.什么是多线程 有了多线程我们就可以让程序同时做多件事情 3.多线程的作用 提高效率 4.线程的应用场景 只要你想让多个事情同时运行就需要用到多线程 比如软件中的耗时操作、所有的聊天软件、所有的服务器 二、并发和并行的概念 1.什么是并发 并发就是同一时刻有多个指令在单个CPU上交替执行。 2.什么是并行 并行就是同一时刻有多个指令在多个CPU上同时执行 3.电脑不是只有一个CPU么这个多个CPU同时执行的并行究竟是什么 其实CPU在市面有很多类型如下 比如2核4线程的CPU就可以同时运行4个线程的任务。 三、多线程的实现方式3种  1.继承Thread类的方式进行实现 用法 1.定义一个类继承Thread类 2.这个类重写run方法 3.在main方法里面创建定义的类的对象 4.通过该对象的.start()方法启动线程 示例代码 public class ThreadDemo1 {public static void main(String[] args) {MyThread myThread1 new MyThread();MyThread myThread2 new MyThread();myThread1.setName(线程1);myThread2.setName(线程2);myThread1.start();myThread2.start();} } class MyThread extends Thread{Overridepublic void run(){for(int i0;i100;i){System.out.println(Thread.currentThread().getName() i);}} } 上面的两个线程的代码run方法是同时执行的并不会等一个线程的循环走完。 注意线程类开启后执行的是run方法的代码  2.实现Runnable接口的方式进行实现 用法 1.自己定义一个类实现Runnable接口 2.重写里面的run方法 3.在main方法创建自己的类的对象 4.将定义的类传递给Thread构造方法创建一个Thread类的对象并开启线程 示例  public class ThreadDemo2 {public static void main(String[] args) {MyThread myThread new MyThread();Thread thread1 new Thread(myThread);Thread thread2 new Thread(myThread);thread1.setName(线程1);thread2.setName(线程2);thread2.start();thread1.start();} } class MyThread implements Runnable{Overridepublic void run() {for (int i 0; i 100; i) {System.out.println(Thread.currentThread().getName()--i);}} } 3.利用Callable接口和Future接口方式实现 前面两种实现方式run方法没有返回值不知道线程实现的结果现在这个第三种方法是有返回值的。 用法 1.创建一个类MyCallable实现callable接口 2.重写call是有返回值的表示多线程运行的结果 3.创建MyCallable的对象表示多线程要执行的任务 4.传递MyCallable对象为参数创建FutureTask的对象作用管理多线程运行的结果 5.传递FutureTask对象为参数创建Thread类的对象并启动表示线程 示例 public class ThreadDemo3 {public static void main(String[] args) throws ExecutionException, InterruptedException {MyCallable mc new MyCallable();FutureTaskInteger ft new FutureTask(mc);Thread t new Thread(ft);t.start();System.out.println(ft.get());} } class MyCallable implements CallableInteger {Overridepublic Integer call() throws Exception {int sum 0;for (int i 0; i 100; i) {sum i;}return sum;} } 结果输出5050 4.三种方式的比较  四、Thread类的常用成员方法 1.七个方法 2.前四个细节 String getName() void setName(String name) 细节         1. 果我们没有给线程设置名字线程也是有默认的名字的                 格式Thread-XX序号从0开始的         2.如果我们要给线程设置名字可以用set方法进行设置也可以构造方法设置 static Thread currentThread() 细节         当JVM虚拟机启动之后会自动的启动多条线程         其中有一条线程就叫做main线程         他的作用就是去调用main方法并执行里面的代码         在以前我们写的所有的代码其实都是运行在main线程当中 static void sleep(long time)    细节         1.哪条线程执行到这个方法那么哪条线程就会在这里停留对应的时间         2.方法的参数就表示睡眠的时间单位毫秒                 1秒 1000毫秒         3.时间到了之后线程会自动的醒来继续执行下面的其他代码 3.线程的优先级 1线程调度 抢占式调度各条线程执行的顺序和时间是不确定的随机 非抢占式调度各条线程执行的顺序是轮流执行和执行时间是差不多的 java中是选取第一种抢占式调度 2优先级1~10 抢占式调度就要涉及到线程的优先级越大执行的顺序越前 于是可以通过Thread类的上面的两个成员方法来设置和获取线程的优先级 没有设置默认就是5 注意这里的优先级是指优先级大的线程先执行的概率比较大而不是百分百比如说有两个一样的方法的线程优先大的线程是有概率计较大的先执行完但还是有小概率执行慢 4.守护线程 当一个线程使用Thread类的etDaemon(boolean on)时这个线程变成守护线程。 细节 这个线程也可以叫做“备胎”线程它将其他线程视为“女神”线程当其他线程结束的时候这个守护线程就会陆续结束觉得自己没必要存在了这就会可能导致守护线程的代码没有全部执行完。 应用场景  上面聊天的场景两个人聊天开两个线程一个聊天一个传输文件如果聊天线程关闭了就没有传输文件的必要了于是将传输文件的线程设置为守护线程。 5.出让/礼让线程 在当前线程的工作不重要时将CPU资源让位给其他线程通过使用Thread类的yield()方法来将当前资源让位给其他同优先级线程 public static void main(String[] args) {Thread t1 new Thread(() - {System.out.println(线程1开始运行);for (int i 0; i 50; i) {if(i % 5 0) {System.out.println(让位);Thread.yield();}System.out.println(1打印i);}System.out.println(线程1结束);});Thread t2 new Thread(() - {System.out.println(线程2开始运行);for (int i 0; i 50; i) {System.out.println(2打印i);}});t1.start();t2.start(); } 观察结果我们发现在让位之后尽可能多的在执行线程2的内容。  6.插入线程 当我们希望一个线程等待另一个线程执行完成后再继续进行我们可以使用Thread类的join()方法来实现线程的插入。 public static void main(String[] args) {Thread t1 new Thread(() - {System.out.println(线程1开始运行);for (int i 0; i 50; i) {System.out.println(1打印i);}System.out.println(线程1结束);});Thread t2 new Thread(() - {System.out.println(线程2开始运行);for (int i 0; i 50; i) {System.out.println(2打印i);if(i 10){try {System.out.println(线程1加入到此线程);t1.join(); //在i10时让线程1加入先完成线程1的内容再继续当前内容} catch (InterruptedException e) {e.printStackTrace();}}}});t1.start();t2.start(); } 线程2执行一半线程1加入先完成线程1的内容再继续线程2的内容  五、线程的生命周期 六、线程的安全问题 1.售票代码引出问题 有100张票售卖一共3个窗口在卖。 下面代码设置三个线程当作三个卖票的窗口看看有什么问题 public class ThreadSafetyProblem {public static void main(String[] args) {MyThread1 myThread1 new MyThread1();MyThread1 myThread2 new MyThread1();MyThread1 myThread3 new MyThread1();myThread1.setName(窗口1);myThread2.setName(窗口2);myThread3.setName(窗口3);myThread1.start();myThread2.start();myThread3.start();} } class MyThread1 extends Thread{//静态变量几个线程共享private static int count 0;public void run(){while(true){try {//这里只能try-catch丢给JVM不能throwsThread.sleep(100); //因为父类的run方法没有throws} catch (InterruptedException e) {throw new RuntimeException(e);}if (count 100){System.out.println(Thread.currentThread().getName() 正在卖第 count张票);}else{break;}}} }2.超卖和重复卖问题 运行后出现的问题结果如下图 三个窗口在同时卖一张票不合法 超卖了仅有100张票    原因 线程的执行是有随机性的cpu的执行权有可能被其他线程抢走。 线程1执行完票数的自增还没来得及打印的时候线程2和线程3完成自增就会导致超卖和重复卖  那么要怎么解决这个安全问题呢下一个点就会讲到解决的方法之一——同步代码块。 七、同步代码块 同步代码块的意思就是把操作共享数据的代码锁起来 1.格式 synchronized(锁){         操作共享数据的代码 } 特点         1.锁默认打开有一个线程进去了锁自动关闭         2.里面的代码全部执行完毕线程出来锁自动打开 2.修改后的售票代码  class MyThread1 extends Thread{//静态变量几个线程共享private static int count 0;//锁对象一定要是唯一的static Object obj new Object();public void run(){while(true){//同步代码块synchronized (obj){try {Thread.sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);}if (count 2000){System.out.println(Thread.currentThread().getName() 正在卖第 count张票);}else {break;}}}} } 运行后的结果票正常售卖从第一张卖到最后一张。  3.细节问题 细节1同步代码块不能放在while循环里面因为放在外的话一个线程拿到锁后就会必须把循环执行完才会释放锁这样的话一个线程就把票都卖完了。 细节2锁的对象必须是唯一的修改后的代码的锁是一个Object对象用static修饰后表示全局共享唯一的对象。也可以使用MyThread.class表示唯一的字节码文件对象 八、同步方法  如果我们要锁的代码是整个方法这个时候就要用到同步方法了 就是把synchronized关键字加到方法上 1.格式 修饰符  synchronized  返回值类型  方法名方法参数{….} 2.特点 特点1同步方法是锁住方法里面所有的代码 特点2锁对象不能自己指定如果方法是非静态的锁对象就是方法所在类对象this                                                  如果方法是静态的锁对象就是当前类的字节码文件对象 3.使用同步方法解决售票问题  示例代码 这段代码与前面不同的是这段代码是使用实现Runnable接口实现的多线程只需要创建一个实现Runnable接口的javabean类的对象所以票数这个变量的内存地址是唯一的所以不用像上面的代码一样用static修饰票数count 注意下面同步方法是非静态的所以锁对象就是MyRunnable类的对象mr public class ThreadSafetyProblem {public static void main(String[] args) {MyRunnable mr new MyRunnable();Thread myThread1 new Thread(mr);Thread myThread2 new Thread(mr);Thread myThread3 new Thread(mr);myThread1.setName(窗口1);myThread2.setName(窗口2);myThread3.setName(窗口3);myThread1.start();myThread2.start();myThread3.start();} } class MyRunnable implements Runnable{int count 0;public void run(){while(true){//同步代码块if (method()) break;}}//锁对象是thisprivate synchronized boolean method() {try {Thread.sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);}if (count 2000){System.out.println(Thread.currentThread().getName() 正在卖第 count张票);}else {return true;}return false;} }4.StringBuffer为什么是线程安全的 虽然StringBuilder和StringBuffer的成员方法是一样的但为什么之前建议在多线程的情况下使用StringBuffer 这是由于StringBuffer的成员方法比较 StringBuilder多了一个Sychronized修饰词保证了线程的安全但是在单线程的情况下还是使用StringBuilder好一些。 九、Lock锁 1.售票代码使用手动上锁  public class ThreadSafetyProblem {public static void main(String[] args) {MyThread1 myThread1 new MyThread1();MyThread1 myThread2 new MyThread1();MyThread1 myThread3 new MyThread1();myThread1.setName(窗口1);myThread2.setName(窗口2);myThread3.setName(窗口3);myThread1.start();myThread2.start();myThread3.start();} } class MyThread1 extends Thread{//静态变量几个线程共享private static int count 0;//创建一个锁对象 用static修饰表示共享唯一Lock lock new ReentrantLock();public void run(){while(true){lock.lock();try {Thread.sleep(10);if (count 2000){System.out.println(Thread.currentThread().getName() 正在卖第 count张票);}else {break;}} catch (InterruptedException e) {throw new RuntimeException(e);} finally {lock.unlock();}}} } 十、死锁 1.示例代码 下面的代码用了锁的嵌套 public class MyThread extends Thread {static Object objA new Object();static Object objB new Object();Overridepublic void run() {//1.循环while (true) {if (线程1.equals(getName())) {synchronized (objA) {System.out.println(线程1拿到了A锁准备拿B锁);//线程1卡在这里synchronized (objB) {System.out.println(线程1拿到了B锁顺利执行完一轮);}}} else if (线程2.equals(getName())) {if (线程2.equals(getName())) {synchronized (objB) {System.out.println(线程2拿到了B锁准备拿A锁);//线程2卡在这里synchronized (objA) {System.out.println(线程2拿到了A锁顺利执行完一轮);}}}}}} }  运行结果 显然两个线程都卡在第一层同步代码的锁那里程序结束不了。 2.如何解决  很简单不要写锁或同步代码块的锁嵌套就行。 十一、生产者和消费者模式 生产者消费者模式是一个十分经典的多线程协作的模式就是要打破两个线程随机执行的规则你一次我一次。 1.流程框图等待唤醒机制 2.涉及的方法 调用 wait() 方法的线程会释放它持有的锁并进入等待状态直到它被其他线程通过调用 notify() 或 notifyAll() 唤醒。 3.步骤  消费者和生产者的代码都按下面的步骤走 1.循环 2.同步代码块(给消费者或生产者上锁) 3.判断共享数据是否到了末尾到了末尾 4.判断共享数据是否到了末尾没有到末尾执行消费者或生产者的核心逻辑 4. 示例代码 (1)桌子代码 public class Desk {/*桌子的作用控制生产者和消费者的执行*/// 判断桌子上有没有食物// 0 没有食物 生产者的线程执行// 1 有食物 消费者的线程执行//这里一般不用boolean类型因为boolean类型只能是true或者false//如果有多条线程int 可以表示多条线程的状态public static int foodFlat 0;// 消费者现在所能吃食物的碗数public static int count 10;//锁对象static Object lock new Object(); } (2)消费者代码 public class Foodie extends Thread {/*1.循环2.同步代码块(给消费者或生产者上锁)3.判断共享数据是否到了末尾到了末尾4.判断共享数据是否到了末尾没有到末尾执行消费者或生产者的核心逻辑*/public void run(){while(true){synchronized (Desk.lock){if (Desk.count 0){//吃不下了直接结束break;}else {//如果桌上没有食物if (Desk.foodFlat 0){try {//进入等待Desk.lock.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}else {//桌上有食物Desk.foodFlat 0;Desk.count--;System.out.println(消费者吃掉了一碗面条还能吃Desk.count碗);//通知唤醒厨师Desk.lock.notify();}}}}} } (3)生产者代码 public class Cook extends Thread {public void run(){while(true){synchronized (Desk.lock){//判断消费者是否吃饱了if (Desk.count0){//吃饱了就结束break;}else {//消费者还能吃//判断桌子上还有食物么//有食物就进入等待if (Desk.foodFlat1){try {Desk.lock.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}else {//没食物//厨师做一碗面条Desk.foodFlat 1;System.out.println(厨师做了一碗面条);//做好就唤醒消费者Desk.lock.notify();}}}}}} (4)main方法 public class Test {public static void main(String[] args) {Desk desk new Desk();Foodie foodie new Foodie();Cook cook new Cook();foodie.setName(吃货);cook.setName(厨师);foodie.start();cook.start();} } (5)执行结果 从运行结果可以看出来消费者和生产者模式可以使多个线程不再随机而是按顺序的来执行。  5.阻塞队列实现唤醒机制 (1)成员方法put和take put方法底层原理 放入一个数据put方法接收数据先使当前线程获得锁这个队列的唤醒等待的线程如果队列满了当前线程进入等待释放当前锁。 take方法底层原理 take方法取出数据先使当前线程获得锁这个队列的唤醒等待的线程如果队列空的当前线程进入等待释放当前锁。 (2)代码实现 用阻塞队列实现消费者和生产者的示例代码  消费者代码 public class Foodie extends Thread {ArrayBlockingQueueString queue;public Foodie(ArrayBlockingQueueString queue){this.queue queue;}public void run() {while(true){try {queue.take();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(吃货吃了一碗面条);}} }生产者代码  public class Cook extends Thread{ArrayBlockingQueueString queue;public Cook(ArrayBlockingQueueString queue) {this.queue queue;}public void run() {while(true){try {queue.put(一碗面);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(厨师做了一碗面条);}} } main方法  public class Test {public static void main(String[] args) {ArrayBlockingQueueString queue new ArrayBlockingQueue(1);Foodie f new Foodie(queue);Cook c new Cook(queue);f.setName(吃货);c.setName(厨师);f.start();c.start();} } 运行结果   看到上面的结果有人会认为厨师连续做了两碗面是不是违反了模式了 其实不然消费者和生产者两条线程还是一条一次轮流执行的重复输出是因为输出的代码放在了锁的外面所以两个线程是随机的抢着输出的厨师做了多少碗面和消费者吃了多少碗的数量还是一样的。厨师放一碗面到队列吃货就拿一碗。 注意锁只在阻塞队列里面即示例代码的put和take方法里面 十二、线程的6种状态 严格的来说线程有7种状态但是线程在进入要运行阶段的时候JVM直接将线程丢给操作系统java就不管了。所以对于java来说线程是有6种状态。如下 十三、Demo  1.Demo1 有100份礼品两人同时发送当剩下的礼品品小于10份分的时候则不再送出 利用多线程模拟该过程并将线程的名字和礼物的剩余数量打印出来 public class MyRunnable implements Runnable{int count 100;Overridepublic void run() {while (true) {synchronized (this) {if (count 10){break;}else {count--;System.out.println(Thread.currentThread().getName() 送出一份礼物剩余 count 份礼物);}}}} } public class Test {public static void main(String[] args) {MyRunnable mr new MyRunnable();Thread t1 new Thread(mr);Thread t2 new Thread(mr);t1.setName(小明);t2.setName(小红);t1.start();t2.start();} } 2.Demo2 public class MyRunnable implements Runnable{double money 100;int count 3;Random rnd new Random();public void run(){synchronized (this) {if (count 0){System.out.println(Thread.currentThread().getName()没抢到);}else if (count 1){count--;System.out.println(Thread.currentThread().getName()抢到了money元);money 0;}else {double get (rnd.nextDouble()*money);System.out.println(Thread.currentThread().getName()抢到了get元);money money - get;count--;}}} } public class Test {public static void main(String[] args) {MyRunnable mr new MyRunnable();Thread t1 new Thread(mr);Thread t2 new Thread(mr);Thread t3 new Thread(mr);Thread t4 new Thread(mr);Thread t5 new Thread(mr);t1.setName(玩家1);t2.setName(玩家2);t3.setName(玩家3);t4.setName(玩家4);t5.setName(玩家5);t1.start();t2.start();t3.start();t4.start();t5.start();} } 3.Demo3 public class MyRunnable implements Runnable{//奖池ArrayListInteger list;public MyRunnable(ArrayListInteger list) {this.list list;}Overridepublic void run() {while (true){synchronized (this) {if (list.isEmpty()){break;}Collections.shuffle(list);System.out.println(Thread.currentThread().getName()又产生了一个list.get(0)元大奖);list.remove(0);}//在锁外面休眠一会这样另外一个线程就先执行输出会好看一点try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}} } public class Test {public static void main(String[] args) {ArrayListInteger list new ArrayList();Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);MyRunnable mr new MyRunnable(list);Thread t1 new Thread(mr);Thread t2 new Thread(mr);t1.setName(抽奖箱1);t2.setName(抽奖箱2);t1.start();t2.start();} } 4.Demo4 多线程统计并求最大值 public class MyRunnable implements Runnable{//奖池ArrayListInteger list;public MyRunnable(ArrayListInteger list) {this.list list;}Overridepublic void run() {//定义一个集合收集每一个抽奖箱每次中奖的金额ArrayListInteger moneys new ArrayList();while (true){synchronized (this) {if (list.isEmpty()){Collections.sort(moneys);System.out.println(在此次抽奖过程中Thread.currentThread().getName()总共产生了moneys.size()个奖项);String string moneys.toString();System.out.println(\t分别为:string.substring(1,string.length()-1)最高奖项为moneys.get(moneys.size() - 1),总计额为moneys.stream().mapToInt(Integer::intValue).sum());break;}Collections.shuffle(list);moneys.add(list.get(0));list.remove(0);}try {Thread.sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);}}} } public class Test {public static void main(String[] args) {ArrayListInteger list new ArrayList();Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);String name1 抽奖箱1;String name2 抽奖箱2;MyRunnable mr new MyRunnable(list);Thread t1 new Thread(mr);Thread t2 new Thread(mr);t1.setName(name1);t2.setName(name2);t1.start();t2.start();} } 5.Demo5多线程之间的比较 由于这里要多线程之间进行比较所以必须要有返回值run方法没有返回值所以使用第三种方法实现多线程即实现Callable接口和Future接口  public class MyCallable implements CallableInteger {//奖池ArrayListInteger list;public MyCallable(ArrayListInteger list) {this.list list;}Overridepublic Integer call(){//定义一个集合收集每一个抽奖箱每次中奖的金额ArrayListInteger moneys new ArrayList();while (true){synchronized (this) {if (list.isEmpty()){Collections.sort(moneys);System.out.println(在此次抽奖过程中Thread.currentThread().getName()总共产生了moneys.size()个奖项);String string moneys.toString();System.out.println(\t分别为:string.substring(1,string.length()-1)最高奖项为moneys.get(moneys.size() - 1),总计额为moneys.stream().mapToInt(Integer::intValue).sum());break;}Collections.shuffle(list);moneys.add(list.get(0));list.remove(0);}try {Thread.sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);}}return moneys.get(moneys.size() - 1);} } public class Test {public static void main(String[] args) throws ExecutionException, InterruptedException {ArrayListInteger list new ArrayList();Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);String name1 抽奖箱1;String name2 抽奖箱2;MyCallable mc new MyCallable(list);FutureTaskInteger ft1 new FutureTask(mc);FutureTaskInteger ft2 new FutureTask(mc);Thread t1 new Thread(ft1,name1);Thread t2 new Thread(ft2,name2);t1.start();t2.start();if (ft1.get()ft2.get()){System.out.println(在此次抽奖过程中,name1中产生了最大奖项该奖项金额为ft1.get()元);}else {System.out.println(在此次抽奖过程中,name2中产生了最大奖项该奖项金额为ft2.get()元);}} }十四、多线程的内存图  十五、线程池 1.核心原理 1创建一个池子池子中是空的 2提交任务时池子会创建新的线程对象任务执行完毕线程归还给池子         下回再次提交任务时不需要创建新的线程直接复用已有的线程即可 3但是如果提交任务时池子中没有空闲线程也无法创建新的线程任务就会排队等待 2.操作步骤 1创建线程池对象 2提交任务(提交线程) 3任务都执行完毕后关闭线程池 注意一般的服务器线程池是不会关闭的比如王者游戏24小时都能玩 3.自定义线程池 把一个餐厅的运营的七大核心因素看作线程的参数 (1)两种情况三个临界点 A.线程池的参数如下提交的任务数小于333因此不会触发任务过多解决方案8个任务从核心线程开始放然后放队伍发现不够放了于是找来临时工临时线程放多余的两个任务。 注意任务并不是先放就先执行比如下面任务78后放比在排队的456先走。 B.下面这种情况和上面不同的是提交的任务数量超过了333于是最后一个任务触发了任务拒绝策略。 其他和上面相同   三个临界点  (2)任务拒绝策略 (3)创建一个线程池 构造方法和参数如下 使用这个线程池就提交任务就行pool.submit(线程任务) (4)最大并行数  在多线程编程中指同时运行的线程数量的上限。 下面代码可以获得java可用的处理器的数目即可同时运行线程的最大数量 (5)线程池多大合适 cpu计算时间和等待时间可以通过插件thread dump计算统计
http://www.hkea.cn/news/14546624/

相关文章:

  • 品牌网站建设小8蝌蚪如何在手机上开自己的网站
  • 郑州七彩网站建设公司怎么样虚拟主机有几种类型
  • 天天seo站长工具域名提交收录
  • 网站访问量查询工具广州做网站建设哪家专业
  • 优秀个人网站模板下载网站建设策划方
  • 微信网站建站平台做电商一般月入多少钱
  • 网站大全app下载推广公司业务发朋友圈
  • 那块做微信平台网站小程序商店有哪些
  • 网站建设安全吗台州市临海建设局网站
  • 网站推广营销方法专业提供网站建设服务是什么
  • 网站备案 座机百度销售岗位怎么样
  • 网站新闻页面设计怎么才能建立一个网站卖东西
  • 国家建设部网站查询模板网站建设方案
  • 电商网站开发流程合肥网站推广优化公司
  • 温江建网站kol推广是什么意思
  • 商丘网站建设运营公司越秀网站建设
  • 出国做网站工作手机cms建站系统
  • 成都便宜网站建设全国妇联官方网站儿童之家建设
  • 争对银行排队做一网站做生物卷子的网站
  • 天网站建设子网站如何做
  • 网站建设 中标乐山市住房和城乡规划建设局网站
  • 成都建设网官方网站wordpress 文件存储
  • 响应式网站研究现状移动应用开发适合女生吗
  • 宁波网站建设制作环境设计专业就业方向
  • 重庆做网站letidewordpress+缩略图截图
  • 网站建设有哪些技术html做企业门户网站
  • 公司网站域名续费科技公司怎么取名字
  • 快速做网站详情页公司网站建设哪家快
  • 江门cms建站wordpress主题结构讲解视频教程
  • 做视频网站要什么主机兰州专业做网站的公司有哪些