中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

望城區(qū)政府門戶網(wǎng)站建設(shè)局電商平臺推廣公司

望城區(qū)政府門戶網(wǎng)站建設(shè)局,電商平臺推廣公司,建設(shè)網(wǎng)站過程中,濟(jì)南網(wǎng)站建設(shè)線程池和ThreadLocal詳解線程池池化模式:線程池里的線程數(shù)量設(shè)定為多少比較合適?添加線程規(guī)則:實(shí)現(xiàn)原理:線程池實(shí)現(xiàn)任務(wù)復(fù)用的原理線程池狀態(tài):Executors 創(chuàng)線程池工具類手動(dòng)創(chuàng)建(更推薦):自動(dòng)創(chuàng)…

線程池和ThreadLocal詳解

  • 線程池
      • 池化模式:
      • 線程池里的線程數(shù)量設(shè)定為多少比較合適?
      • 添加線程規(guī)則:
      • 實(shí)現(xiàn)原理:
      • 線程池實(shí)現(xiàn)任務(wù)復(fù)用的原理
      • 線程池狀態(tài):
    • Executors 創(chuàng)線程池工具類
        • 手動(dòng)創(chuàng)建(更推薦):
      • 自動(dòng)創(chuàng)建:
    • ExecutorService 執(zhí)行線程池
      • 運(yùn)行:
      • 關(guān)閉:
      • 其他:
      • execut() 執(zhí)行流程:
    • 鉤子方法
  • ThreadLocal
      • 優(yōu)點(diǎn):
      • 創(chuàng)建:
    • 使用場景
      • 一、每個(gè)線程需要一個(gè)獨(dú)享的對象
      • 二、每個(gè)線程內(nèi)需要保存全局變量(例如在攔截器中獲取用戶信息)
    • 原理
    • 注意
      • 內(nèi)存泄漏:
      • 如何避免內(nèi)存泄露(阿里規(guī)約)
      • 空指針異常:

線程池

java線程池是 JDK1.5提供 juc(java.util.concurrent)包中,底層實(shí)現(xiàn)其實(shí)就是 Callable 和 Future 接口
請?zhí)砑訄D片描述

池化模式:

  • 將大量我們需要的對象提前創(chuàng)建好,放在一個(gè)池(概念),對象提前創(chuàng)建完成,也不需要銷毀對象,所以說使用效率比較好。
    • 優(yōu)點(diǎn):使用效率較好,避免對象的 重復(fù)創(chuàng)建 和 銷毀。
    • 缺點(diǎn):內(nèi)存占有較高,池的數(shù)量難以把控。

線程池里的線程數(shù)量設(shè)定為多少比較合適?

  • CPU 密集型(加密、計(jì)算hash等)︰最佳線程數(shù)為CPU核心數(shù)的 1-2 倍左右。
  • 耗時(shí) IO 型(讀寫數(shù)據(jù)庫、文件、網(wǎng)絡(luò)讀寫等)︰最佳線程數(shù)一般會(huì)大于 CPU 核心數(shù)很多。
  • 參考 Brain Goetz 推薦的計(jì)算方法︰線程數(shù) = CPU核心數(shù) * (1+平均等待時(shí)間/平均工作時(shí)間)

添加線程規(guī)則:

  1. 最開始線程總數(shù)小于 corePoolSize 時(shí),即使有線程處于空閑狀態(tài)新任務(wù)到來時(shí),也會(huì)創(chuàng)建一個(gè)新線程。
  2. 直到線程數(shù)等于 corePoolSize,再來任務(wù)時(shí),會(huì)把任務(wù)放入隊(duì)列去等待。
  3. 直到隊(duì)列也滿了,如果此時(shí)線程數(shù)小于 maximumPoolSize,則會(huì)再創(chuàng)建新線程來執(zhí)行任務(wù)。
  4. 如果隊(duì)列已滿,并且線程數(shù)已經(jīng)擴(kuò)大到等于 maximumPoolSize時(shí),再嘗試添加任務(wù)時(shí),會(huì)被拒絕。
    請?zhí)砑訄D片描述
  • 特點(diǎn):
    • 若 corePoolSize == maximumPoolSize,則相當(dāng)于 newFixedThreadPool();
    • 線程池希望保持較少的線程數(shù),并且只有在負(fù)載變得很大時(shí)才增加它。
    • 只有在隊(duì)列填滿時(shí)才創(chuàng)建多于corePoolSize的線程,如果使用的是無界隊(duì)列,那么線程數(shù)就不會(huì)超過 corePoolSize。

實(shí)現(xiàn)原理:

  • 線程池組成部分
    • 線程池管理器
    • 工作線程
    • 任務(wù)隊(duì)列
    • 任務(wù)接口(Task)

線程池實(shí)現(xiàn)任務(wù)復(fù)用的原理

  • 相同線程執(zhí)行不同任務(wù)
    • 不需要重復(fù)的啟動(dòng)線程,循環(huán)的從隊(duì)列中取出新任務(wù)并執(zhí)行其 run() 方法。

線程池狀態(tài):

  • RUNNING:接受新任務(wù) 并 處理排隊(duì)任務(wù)。
  • SHUTDOWN:不接受新任務(wù),但處理排隊(duì)任務(wù)。
  • STOP:不接受新任務(wù),也不處理排隊(duì)任務(wù),并中斷正在進(jìn)行的任務(wù)。
  • TIDYING:所有任務(wù)都已終止,workerCount 為零時(shí),線程會(huì)轉(zhuǎn)換到 TIDYING 狀態(tài),并將運(yùn)行 terminate() 鉤子方法。
    TERMINATED:terminate()鉤子方法 運(yùn)行完成。

Executors 創(chuàng)線程池工具類

  • 根據(jù)情況,我們創(chuàng)建很多種不同場景的線程池 Executors.new…();
  • 創(chuàng)建線程池返回 ExecutorService 類對象。

手動(dòng)創(chuàng)建(更推薦):

new ThreadPoolExecutor(7個(gè)參數(shù))

  • 最原始的線程池,所有其他的線程池底層都是用的此線程池實(shí)現(xiàn)的。

  • 前== 五個(gè)參數(shù) ==為必須參數(shù),面試題經(jīng)常考問!!!

  • 1、 corePoolSize核心線程數(shù),線程池中始終存活的線程數(shù)。

  • 2、 maximumPoolSize最大線程數(shù)

    • 線程池中允許的最大線程數(shù),當(dāng)線程池的任務(wù)隊(duì)列滿了之后可以創(chuàng)建的最大線程數(shù)。
  • 3、 keepAliveTime:最大線程數(shù)可以存活的時(shí)間

    • 如果線程池當(dāng)前的線程數(shù)多于 corePoolSize,那么如果多余的線程空閑時(shí)間超過 keepAliveTime,它們就會(huì)被終止。
  • 4、unit時(shí)間單位是和參數(shù) 3 存活時(shí)間配合使用的,合在一起用于設(shè)定線程的存活時(shí)間 ,參數(shù) keepAliveTime 的時(shí)間單位有以下 7 種可選:

    • TimeUnit.DAYS:天; TimeUnit.HOURS:小時(shí); TimeUnit.MINUTES:分; TimeUnit.SECONDS:秒
    • TimeUnit.MILLISECONDS:毫秒; TimeUnit.MICROSECONDS:微妙; TimeUnit.NANOSECONDS:納秒
  • 5、 workQueue:一個(gè)阻塞隊(duì)列,用來存儲(chǔ)線程池等待執(zhí)行的任務(wù),均為線程安全,它包含以下 7 種類型:

    • ArrayBlockingQueue:一個(gè)由數(shù)組結(jié)構(gòu)組成的有界阻塞隊(duì)列。
    • LinkedBlockingQueue:一個(gè)由鏈表結(jié)構(gòu)組成的無界阻塞隊(duì)列。
    • SynchronousQueue:直接交接,一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列,即直接提交給線程不保持它們。
    • PriorityBlockingQueue:一個(gè)支持優(yōu)先級排序的無界阻塞隊(duì)列。
    • DelayQueue:延遲隊(duì)列:一個(gè)使用優(yōu)先級隊(duì)列實(shí)現(xiàn)的無界阻塞隊(duì)列,只有在延遲期滿時(shí)才能從中提取元素。
    • LinkedTransferQueue : 一個(gè)由鏈表結(jié)構(gòu)組成的無界阻塞隊(duì)列,與 SynchronousQueue 類似,還含有非阻塞方法。
    • LinkedBlockingDeque:一個(gè)由鏈表結(jié)構(gòu)組成的雙向阻塞隊(duì)列。
  • 6、threadFactory:線程工廠,主要用來創(chuàng)建線程。

    • 默認(rèn)為正常優(yōu)先級、非守護(hù)線程(Executors.defaultThreadFactory())。
    • 創(chuàng)建出來的線程都在同一個(gè)線程組。
    • 如果自己指定 ThreadFactory,那么就可以改變線程名、線程組、優(yōu)先級、是否是守護(hù)線程等。
  • 7、handler:拒絕策略,拒絕處理任務(wù)時(shí)的策略,系統(tǒng)提供了 4 種可選

    • AbortPolicy默認(rèn)策略,拒絕并直接拋出異常。
    • DiscardPolicy:默默的丟棄任務(wù),不會(huì)通知。
    • DiscardOldestPolicy:丟棄隊(duì)列中存在時(shí)間最久的任務(wù)。
    • CallerRunsPolicy:讓提交任務(wù)的線程去執(zhí)行。
      • 優(yōu)點(diǎn):不會(huì)放棄執(zhí)行任務(wù),并且能夠使提交任務(wù)的速度降低下來(負(fù)反饋)
  • 很多公司都 【強(qiáng)制使用】 這個(gè)最原始的方式創(chuàng)建線程池,因?yàn)檫@是可控的。

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(500, 2000, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>());

自動(dòng)創(chuàng)建:

  • Executors.newFixedThreadPool(int n):創(chuàng)建一個(gè) 可重用固定大小 的線程池,可控制并發(fā)的線程數(shù),超出的線程會(huì)在隊(duì)列中等待。
    • 適用場景:并發(fā)量不會(huì)發(fā)生變化(并發(fā)量的變化非常小)
new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
  • Executors.newCachedThreadPool([int n]):創(chuàng)建一個(gè)== 可緩存 ==的線程池。
    • 若線程數(shù)超過處理所需,緩存一段時(shí)間后會(huì)回收,若線程數(shù)不夠,則新建線程。
    • 適用場景:并發(fā)量變化比較明顯,建議使用此方法
new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
  • ScheduledExecutorService Executors.newScheduledThreadPool(): 創(chuàng)建 延遲 后的線程池,可以設(shè)置間隔。
    • 返回 ScheduledExecutorService類 對象:
      • schedule(Runnable command, long delay, TimeUnit unit):指定延遲時(shí)間后創(chuàng)建線程。
      • scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit):
        • 在給定的初始延遲后首先啟用,然后根據(jù)間隔時(shí)間 period 執(zhí)行。
(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new DelayedWorkQueue());
  • Executors.newSingleThreadExecutor(): 單線程的線程池,只會(huì)用唯一的工作線程來執(zhí)行任務(wù)。
new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
  • Executors.newWorkStealingPool():創(chuàng)建一個(gè)搶占式執(zhí)行的線程池(任務(wù)執(zhí)行順序不確定)
    • 注意此方法只有在 JDK 1.8+ 版本中才能使用。

ExecutorService 執(zhí)行線程池

運(yùn)行:

  • execute(Runnable task):運(yùn)行線程。
  • submit():運(yùn)行線程(更加強(qiáng)大),常用于創(chuàng)建Runnable匿名內(nèi)部類
    請?zhí)砑訄D片描述
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {final int idx = i;executor.submit(() -> System.out.println(Thread.currentThread().getName() + "————》" + idx));
}

關(guān)閉:

  • shutdown():拒絕新任務(wù),等 正在執(zhí)行 以及 阻塞隊(duì)列 中的任務(wù)執(zhí)行完畢后就停止線程池。
  • isShutdown():判斷線程池是否已經(jīng)開始了關(guān)閉工作,也就是是否執(zhí)行了 shutdown 或者 shutdownNow 方法。。
  • IsTerminated():判斷線程池是否已經(jīng)完全終止。(正在執(zhí)行、阻塞隊(duì)列都已清空)
  • awaitTermination(long timeout, TimeUnit unit):檢測在指定時(shí)間內(nèi)(此時(shí)當(dāng)前線程阻塞),線程池是否會(huì)完全終止。
  • List< Runnable> shutdownNow():立刻完全停止線程池,中斷正在執(zhí)行的線程,并將阻塞隊(duì)列里的線程返回。
    • 線程 run() 方法在運(yùn)行期間被中斷會(huì)拋出 InterruptedException,可以使用 catch 捕獲。

其他:

  • BlockingQueuegetQueue():獲取阻塞隊(duì)列

execut() 執(zhí)行流程:

public void execute(Runnable command) {if (command == null)throw new NullPointerException();int c = ctl.get();if (workerCountOf(c) < corePoolSize) {if (addWorker(command, true))return;c = ctl.get();}// 線程池正在運(yùn)行,且隊(duì)列沒滿if (isRunning(c) && workQueue.offer(command)) {int recheck = ctl.get();// 線程停止運(yùn)行了,則刪除任務(wù),并拒絕if (! isRunning(recheck) && remove(command))reject(command);// 核心工作線程沒有了,創(chuàng)建一個(gè)空的核心工作線程else if (workerCountOf(recheck) == 0)addWorker(null, false);}// 隊(duì)列滿了,嘗試添加額外線程,此處 false 代表添加的是額外線程(<= 最大線程數(shù))else if (!addWorker(command, false))reject(command);
}

鉤子方法

  • 在每個(gè)任務(wù)執(zhí)行前后進(jìn)行操作

    • 例如:日志、統(tǒng)計(jì)、暫停
  • 繼承自線程池 ThreadPoolExecutor ,并重寫構(gòu)造器

  • 可重寫方法:

    • beforeExecute():線程執(zhí)行前的操作。
    • afterExecute():線程執(zhí)行后的操作。

示例:實(shí)現(xiàn)線程池的暫停、恢復(fù)操作,(省略了構(gòu)造器)

public class PauseableThreadPool extends ThreadPoolExecutor {// 線程池是否處于暫停狀態(tài)private boolean isPaused;private final ReentrantLock lock = new ReentrantLock();private Condition unPaused = lock.newCondition();public void pause() {lock.lock();try {isPaused = true;} finally {lock.unlock();}}@Overrideprotected void beforeExecute(Thread t, Runnable r) {super.beforeExecute(t, r);lock.lock();try {while (isPaused) {unPaused.await();}} catch (InterruptedException e) {throw new RuntimeException(e);} finally {lock.unlock();}}public void resume() {lock.lock();try {isPaused = false;unPaused.notifyAll();} finally {lock.unlock();}}
}

ThreadLocal

  • 在 JDK1.2 的版本中已經(jīng)為線程對象提供了副本對象,特點(diǎn)是:每一個(gè)線程都 獨(dú)立擁有 ThreadLocal 對象。

  • 作用1:在任何線程的方法中都可以輕松獲取到該對象。
    在 ThreadLocal 初始化時(shí)加入對象。

  • 作用2:讓某個(gè)需要用到的對象在線程間隔離(每個(gè)線程都有自己的獨(dú)立的對象)
    在線程中 set 對象。

  • ThreadLocal 不支持繼承

    • 同一個(gè) ThreadLocal 變量在父線程中被設(shè)置值后,那么在子線程中是獲取不到的。
  • InheritableThreadLocal 類是可以做到支持繼承性。

優(yōu)點(diǎn):

  • 達(dá)到線程安全。
  • 不需要加鎖,提高執(zhí)行效率。
  • 更高效地利用內(nèi)存、節(jié)省開銷。
    • 相比于場景一每個(gè)任務(wù)都新建一個(gè) SimpleDateFormat,顯然用 ThreadLocal 可以節(jié)省內(nèi)存和開銷
  • 免去傳參的繁瑣
    • 不需要每次都傳同樣的參數(shù)
    • ThreadLocal使得代碼耦合度更低,更優(yōu)雅

創(chuàng)建:

  • 一定要將 ThreadLocal 定義成 靜態(tài)變量 static
  • ThreadLocal 需要一個(gè)泛型;
public static ThreadLocal<String> threadLocal1 = new Thread<>();
public static ThreadLocal<SimpleDateFormat> threadLocal2 = ThreadLocal.withInitial(() ->new SimpleDateFormat("yyyy-MM-dd hh:mm:ss")
); // 初始化并設(shè)置值
  • get():獲取 ThreadLocal 中當(dāng)前線程共享的變量的值。

    • 在 線程開啟(或調(diào)用 remove())后第一次調(diào)用 get() 的時(shí)候,會(huì)調(diào)用 initialValue() 來得到值。
  • remove():移除 ThreadLocal中當(dāng)前線程共享的變量的值。

    • 最后 一定 要移除值!!!,否則很容易出現(xiàn) 內(nèi)存溢出。
  • initialValue():該方法會(huì)返回當(dāng)前線程對應(yīng)的 “初始值”,這是一個(gè)延遲加載的方法。默認(rèn)為 null。

    • ThreadLocal.withInitial():初始化 ThreadLocal 并設(shè)置 initialValue()。
  • set():設(shè)置 ThreadLocal 中當(dāng)前線程共享的變量的值。

  • set 和 setInitialValue 結(jié)果都是調(diào)用 map.set,只不過是起點(diǎn)和入口不一樣。

public static ThreadLocal<SimpleDateFormat> threadLocal2 = ThreadLocal.withInitial(() ->new SimpleDateFormat("yyyy-MM-dd hh:mm:ss")
);
@Test
void contextLoads() {ExecutorService executorService = Executors.newFixedThreadPool(10);for (int i = 0; i < 1000; ++i) {final int finalI = i;executorService.submit(() ->System.out.println(threadLocal2.get().format(new Date(1000 * finalI))));}executorService.shutdownNow();
}

使用場景

一、每個(gè)線程需要一個(gè)獨(dú)享的對象

  • 通常是工具類,典型需要使用的類有 SimpleDateFormat 和 Random
  • 比喻∶教材只有一本,一起做筆記有線程安全問題。復(fù)印后就沒問題。
  • 示例:
    • 線程池有1000個(gè)線程,每個(gè)線程都要使用 SimpleDateFormat 工具類,若直接使用,則會(huì)創(chuàng)建 1000 個(gè)工具類,開銷巨大。
    • 這時(shí)可以創(chuàng)建一個(gè) static 的 SimpleDateFormat 對象,讓線程池的每個(gè)核心線程都使用這個(gè)靜態(tài)對象,就防止了重復(fù)的創(chuàng)建。
      • 但是,由于 SimpleDateFormat 類是線程不安全的,會(huì)出現(xiàn)重復(fù)的計(jì)算結(jié)果。
      • 此時(shí),可能會(huì)想到通過加鎖,確實(shí)能使結(jié)果正確,但這樣同一時(shí)間就只有一個(gè)線程運(yùn)行了,那何必高并發(fā)呢?
    • 這時(shí),就可以使用 ThreadLocal 了,讓每個(gè)核心線程內(nèi)部都有自己獨(dú)有的 SimpleDateFormat 對象,如圖:
      請?zhí)砑訄D片描述
public static ThreadLocal<SimpleDateFormat> threadLocal2 = ThreadLocal.withInitial(() ->new SimpleDateFormat("yyyy-MM-dd hh:mm:ss")
);
@Test
void contextLoads() {ExecutorService executorService = Executors.newFixedThreadPool(10);for (int i = 0; i < 1000; ++i) {final int finalI = i;executorService.submit(() ->System.out.println(threadLocal2.get().format(new Date(1000 * finalI))));}executorService.shutdownNow();
}

二、每個(gè)線程內(nèi)需要保存全局變量(例如在攔截器中獲取用戶信息)

  • 可以讓不同方法直接使用,避免參數(shù)傳遞的麻煩

原理

  • ThreadLocal 底層是將 值 存放在線程的 ThreadLocalMap 中的。
    • 通過 getMap(Thread.currentThread()) 獲取 ThreadLocalMap 對象。

請?zhí)砑訄D片描述

注意

內(nèi)存泄漏:

  • 內(nèi)存泄露為 程序在申請內(nèi)存后,無法釋放已申請的內(nèi)存空間,一次內(nèi)存泄露危害可以忽略,但內(nèi)存泄露堆積后果很嚴(yán)重,無論多少內(nèi)存,遲早會(huì)被占光,廣義并通俗的說,就是:不再會(huì)被使用的對象或者變量占用的內(nèi)存 不能被回收,就是內(nèi)存泄露。

  • 由于 ThreadLocalMap 繼承了 WeakReference 類,屬于弱引用對象。

    • 弱引用,JVM進(jìn)行垃圾回收時(shí),無論內(nèi)存是否充足,都會(huì)回收被弱引用關(guān)聯(lián)的對象。在java中,用java.lang.ref.WeakReference 類來表示??梢栽诰彺嬷惺褂萌跻谩?/li>
  • ThreadLocalMap 的每個(gè) Entry 都是一個(gè)對 key 的弱引用,同時(shí)是一個(gè)對 value 的強(qiáng)引用。

  • 正常情況下,當(dāng)線程終止,保存在 ThreadLocal 里的 value 會(huì)被垃圾回收,因?yàn)闆]有任何強(qiáng)引用了但是,如果線程不終止(比如線程需要保持很久),那么 key 對應(yīng)的 value 就不能被回收,因?yàn)橛幸韵碌?調(diào)用鏈:

    • Thread —> ThreadLocalMap —>Entry ( key為null) —> Value
  • 因?yàn)?value 和 Thread 之間還存在這個(gè)強(qiáng)引用鏈路,所以導(dǎo)致 value 無法回收,就可能會(huì)出現(xiàn) OOM

    • ThreadLocalMap 也有相應(yīng)的處理方法(在 resize() 中):掃描 key 為 null 的Entry,并把對應(yīng)的 value 設(shè)置為 null
      • 但前提是得調(diào)用 map.set() 或 remove() 。
  • 如果一個(gè)ThreadLocal 不被使用,就可能導(dǎo)致value的內(nèi)存泄漏

如何避免內(nèi)存泄露(阿里規(guī)約)

  • 調(diào)用 remove 方法,就會(huì)刪除對應(yīng)的 Entry 對象,可以避免內(nèi)存泄漏,所以使用完 ThreadLocal 之后,應(yīng)該調(diào)用 remove方法。

空指針異常:

  • 在創(chuàng)建 ThreadLcal時(shí)泛型是 包裝類,如 Long,而若獲取 value 時(shí),接收返回值的對象只是基本數(shù)據(jù)類型時(shí),有可能會(huì)拆箱錯(cuò)誤。
    • 比如,在 ThreadLocal 沒有設(shè)置值時(shí),默認(rèn)是 null,而將 null 賦給 long,就會(huì) 空指針異常。
      • 若使用的是包裝類 Long,則不會(huì)空指針異常。
  • 因此,在接收 get() 返回值時(shí),不建議使用 基本數(shù)據(jù)類型。
http://www.risenshineclean.com/news/56979.html

相關(guān)文章:

  • 專業(yè)做網(wǎng)站公司 前景sem是什么意思
  • 網(wǎng)站優(yōu)化搜索查詢網(wǎng)站收錄
  • 企業(yè)網(wǎng)站建設(shè)方案新聞百度導(dǎo)航和百度地圖
  • 網(wǎng)站建設(shè)行業(yè)淘寶裝修模板排行榜軟件
  • 有什么網(wǎng)站可以做家教軟文廣告投放平臺
  • 上海裝修做網(wǎng)站的倒閉了百度seo排名優(yōu)化公司哪家強(qiáng)
  • 蘭州網(wǎng)站哪里做怎么做推廣和宣傳平臺
  • 戀愛網(wǎng)站建設(shè)谷歌推廣怎么樣
  • 免費(fèi)合同模板網(wǎng)站海底撈口碑營銷
  • 成都網(wǎng)站建設(shè)服務(wù)全搜網(wǎng)
  • 懷化市委網(wǎng)站網(wǎng)站快速排名互點(diǎn)軟件
  • 杭州盤石做網(wǎng)站專業(yè)嗎做百度網(wǎng)站一年多少錢
  • 如果在網(wǎng)站暗藏鏈接商城做推廣廣安seo外包
  • 娛樂網(wǎng)站模板手機(jī)網(wǎng)頁設(shè)計(jì)制作網(wǎng)站
  • 阿里網(wǎng)站建設(shè)優(yōu)秀營銷軟文100篇
  • 微友說是做網(wǎng)站維護(hù)讓幫忙投注網(wǎng)店代運(yùn)營騙局
  • 做網(wǎng)站博客怎么推廣雅思培訓(xùn)班價(jià)格一覽表
  • 做智能家居網(wǎng)站需要的參考文獻(xiàn)關(guān)鍵詞優(yōu)化公司推薦
  • 網(wǎng)站建設(shè)報(bào)價(jià)方案下載企業(yè)網(wǎng)站模板建站
  • 專業(yè)的app網(wǎng)站開發(fā)百度關(guān)鍵詞優(yōu)化多久上首頁
  • 可直接打開網(wǎng)站的網(wǎng)頁地推任務(wù)網(wǎng)
  • 網(wǎng)站安全如何做百度seo在線優(yōu)化
  • flask做的購物網(wǎng)站互聯(lián)網(wǎng)推廣廣告
  • 如何做網(wǎng)站推廣 求指點(diǎn)網(wǎng)絡(luò)建設(shè)推廣
  • 質(zhì)量好網(wǎng)站建設(shè)哪家便宜網(wǎng)站優(yōu)化費(fèi)用報(bào)價(jià)明細(xì)
  • 大型商業(yè)廣場網(wǎng)站建設(shè)免費(fèi)b2b平臺推廣
  • 做網(wǎng)站后端需要什么語言競價(jià)托管多少錢
  • 個(gè)人網(wǎng)頁設(shè)計(jì)包含html和css南寧網(wǎng)站優(yōu)化公司電話
  • 懷遠(yuǎn)做網(wǎng)站電話溫州seo招聘
  • 網(wǎng)絡(luò)規(guī)劃設(shè)計(jì)師自學(xué)百度小程序優(yōu)化排名