Java并發(fā)編程中線程池工作原理的示例分析,相信很多沒有經(jīng)驗(yàn)的人對(duì)此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個(gè)問題。
創(chuàng)新互聯(lián)建站公司2013年成立,先為衡陽(yáng)縣等服務(wù)建站,衡陽(yáng)縣等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為衡陽(yáng)縣企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。
ThreadPoolExecutor實(shí)現(xiàn)的頂層接口是Executor,在接口Executor中用戶無需關(guān)注如何創(chuàng)建線程,如何調(diào)度線程來執(zhí)行任務(wù),用戶只需提供Runnable對(duì)象,將任務(wù)的運(yùn)行邏輯提交到執(zhí)行器Executor中,由Executor框架完成線程的調(diào)配和任務(wù)的執(zhí)行部分。
ExecutorService接口增加了一些能力
擴(kuò)充執(zhí)行任務(wù)的能力,補(bǔ)充可以為一個(gè)或一批異步任務(wù)生成Future的方法;
提供了管控線程池的方法,比如停止線程池的運(yùn)行。
AbstractExecutorService則是上層的抽象類:
將執(zhí)行任務(wù)的流程串聯(lián)了起來,保證下層的實(shí)現(xiàn)只需關(guān)注一個(gè)執(zhí)行任務(wù)的方法即可。
ThreadPoolExecutor實(shí)現(xiàn)最復(fù)雜的運(yùn)行部分:
可以自動(dòng)創(chuàng)建、管理和復(fù)用指定數(shù)量的一組線程,適用方只需提交任務(wù)即可線程安全,ThreadPoolExecutor內(nèi)部有狀態(tài)、核心線程數(shù)、非核心線程等屬性,廣泛使用了CAS和AQS鎖機(jī)制避免并發(fā)帶來的沖突問題
提供了核心線程、緩沖阻塞隊(duì)列、非核心線程、拋棄策略的概念,可以根據(jù)實(shí)際應(yīng)用場(chǎng)景進(jìn)行組合使用
提供了beforeExecute 和afterExecute()可以支持對(duì)線程池的功能進(jìn)行擴(kuò)展
提高響應(yīng)速度:任務(wù)到達(dá)時(shí),相對(duì)于手工創(chuàng)建一個(gè)線程,直接從線程池中拿線程,速度肯定快很多
提高線程可管理性:線程是稀缺資源,如果無限制地創(chuàng)建,不僅會(huì)消耗系統(tǒng)資源,還會(huì)降低系統(tǒng)穩(wěn)定性,使用線程池可以進(jìn)行同意分配、調(diào)優(yōu)和監(jiān)控。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueueworkQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
corePoolSize:線程池的核心線程數(shù),一般情況下不管有沒有任務(wù)都會(huì)一直在線程池中一直存活,只有在 ThreadPoolExecutor中的方法allowCoreThreadTimeOut(boolean value)設(shè)置為true時(shí),閑置的核心線程會(huì)存在超時(shí)機(jī)制,如果在指定時(shí)間沒有新任務(wù)來時(shí),核心線程也會(huì)被終止,而這個(gè)時(shí)間間隔由第3個(gè)屬性keepAliveTime指定。
maximumPoolSize:線程池所能容納的最大線程數(shù),當(dāng)活動(dòng)的線程數(shù)達(dá)到這個(gè)值后,后續(xù)的新任務(wù)將會(huì)被阻塞。
keepAliveTime:控制線程閑置時(shí)的超時(shí)時(shí)長(zhǎng),超過則終止該線程。一般情況下用于非核心線程,只有在 ThreadPoolExecutor中的方法allowCoreThreadTimeOut(boolean value)設(shè)置為true時(shí),也作用于核心線程。
unit:用于指定keepAliveTime參數(shù)的時(shí)間單位,TimeUnit是個(gè)enum枚舉類型,常用的有:TimeUnit.HOURS(小時(shí))、TimeUnit.MINUTES(分鐘)、TimeUnit.SECONDS(秒) 和 TimeUnit.MILLISECONDS(毫秒)等。
workQueue:線程池的任務(wù)隊(duì)列,通過線程池的execute(Runnable command)方法會(huì)將任務(wù)Runnable存儲(chǔ)在隊(duì)列中。
threadFactory:線程工廠,它是一個(gè)接口,用來為線程池創(chuàng)建新線程的。
handler:拒絕策略,所謂拒絕策略,是指將任務(wù)添加到線程池中時(shí),線程池拒絕該任務(wù)所采取的相應(yīng)策略。
/** * 任務(wù)阻塞隊(duì)列 */ private final BlockingQueueworkQueue; /** * 非公平的互斥鎖(可重入鎖) */ private final ReentrantLock mainLock = new ReentrantLock(); /** * 線程集合一個(gè)Worker對(duì)應(yīng)一個(gè)線程,沒有核心線程的說話,只有核心線程數(shù) */ private final HashSet workers = new HashSet (); /** * 配合mainLock通過Condition能夠更加精細(xì)的控制多線程的休眠與喚醒 */ private final Condition termination = mainLock.newCondition(); /** * 線程池中線程數(shù)量曾經(jīng)達(dá)到過的最大值。 */ private int largestPoolSize; /** * 已完成任務(wù)數(shù)量 */ private long completedTaskCount; /** * ThreadFactory對(duì)象,用于創(chuàng)建線程。 */ private volatile ThreadFactory threadFactory; /** * 拒絕策略的處理句柄 * 現(xiàn)在默認(rèn)提供了CallerRunsPolicy、AbortPolicy、DiscardOldestPolicy、DiscardPolicy */ private volatile RejectedExecutionHandler handler; /** * 線程池維護(hù)線程(超過核心線程數(shù))所允許的空閑時(shí)間 */ private volatile long keepAliveTime; /** * 允許線程池中的核心線程超時(shí)進(jìn)行銷毀 */ private volatile boolean allowCoreThreadTimeOut; /** * 線程池維護(hù)線程的最小數(shù)量,哪怕是空閑的 */ private volatile int corePoolSize; /** * 線程池維護(hù)的最大線程數(shù)量,線程數(shù)超過這個(gè)數(shù)量之后新提交的任務(wù)就需要進(jìn)入阻塞隊(duì)列 */ private volatile int maximumPoolSize;
核心線程數(shù)為0,總線程數(shù)量閾值為Integer.MAX_VALUE,即可以創(chuàng)建無限的非核心線程
newCachedThreadPool是一個(gè)可根據(jù)需要?jiǎng)?chuàng)建新線程的線程池,但是在以前構(gòu)造的線程可用時(shí)將重用它們。對(duì)于執(zhí)行很多短期異步任務(wù)的程序而言,這些線程池通??商岣叱绦蛐阅堋U{(diào)用 execute() 將重用以前構(gòu)造的線程(如果線程可用)。如果現(xiàn)有線程沒有可用的,則創(chuàng)建一個(gè)新線程并添加到池中。終止并從緩存中移除那些已有 60秒鐘未被使用的線程。因此,長(zhǎng)時(shí)間保持空閑的線程池不會(huì)使用任何資源。注意,可以使用 ThreadPoolExecutor構(gòu)造方法創(chuàng)建具有類似屬性但細(xì)節(jié)不同(例如超時(shí)參數(shù))的線程池。
會(huì)出下面大量的線程對(duì)象,導(dǎo)致的OOM
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue()); }
先執(zhí)行SynchronousQueue的offer方法提交任務(wù),并查詢線程池中是否有空閑線程來執(zhí)行SynchronousQueue的poll方法來移除任務(wù)。如果有,則配對(duì)成功,將任務(wù)交給這個(gè)空閑線程,否則,配對(duì)失敗,創(chuàng)建新的線程去處理任務(wù)
當(dāng)線程池中的線程空閑時(shí),會(huì)執(zhí)行SynchronousQueue的poll方法等待執(zhí)行SynchronousQueue中新提交的任務(wù)。若等待超過60s,空閑線程就會(huì)終止
執(zhí)行大量短生命周期任務(wù)。因?yàn)閙aximumPoolSize是無界的,所以提交任務(wù)的速度 > 線程池中線程處理任務(wù)的速度就要不斷創(chuàng)建新線程;每次提交任務(wù),都會(huì)立即有線程去處理,因此CachedThreadPool適用于處理大量、耗時(shí)少的任務(wù)。
它適用于需要保證順序地執(zhí)行各個(gè)任務(wù);并且在任意時(shí)間點(diǎn),不會(huì)有多個(gè)線程是活動(dòng)的應(yīng)用場(chǎng)景,SingleThreadExecutor的corePoolSize和maximumPoolSize被設(shè)置為1,使用無界隊(duì)列LinkedBlockingQueue作為線程池的工作隊(duì)列
newSingleThreadExecutor創(chuàng)建是一個(gè)單線程池,也就是該線程池只有一個(gè)線程在工作,所有的任務(wù)是串行執(zhí)行的,如果這個(gè)唯一的線程因?yàn)楫惓=Y(jié)束,那么會(huì)有一個(gè)新的線程來替代它,此線程池保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行。
當(dāng)線程池中沒有線程時(shí),會(huì)創(chuàng)建一個(gè)新線程來執(zhí)行任務(wù)。
當(dāng)前線程池中有一個(gè)線程后,將新任務(wù)加入LinkedBlockingQueue
線程執(zhí)行完第一個(gè)任務(wù)后,會(huì)在一個(gè)無限循環(huán)中反復(fù)從LinkedBlockingQueue獲取任務(wù)來執(zhí)行 。
**適用于串行執(zhí)行任務(wù)場(chǎng)景**
會(huì)存在出現(xiàn)阻塞隊(duì)列堆積過大,導(dǎo)致的OOM
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue())); }
corePoolSize等于maximumPoolSize,所以線程池中只有核心線程,使用無界阻塞隊(duì)列LinkedBlockingQueue作為工作隊(duì)列
適用于處理CPU密集型的任務(wù),確保CPU在長(zhǎng)期被工作線程使用的情況下,盡可能的少的分配線程,即適用執(zhí)行長(zhǎng)期的任務(wù)。
newFixedThreadPool:創(chuàng)建固定大小的線程池,每次提交一個(gè)任務(wù)就創(chuàng)建一個(gè)線程,直到線程達(dá)到線程池的最大大小,線程池的大小一旦達(dá)到最大值就會(huì)保持不變,如果某個(gè)線程因?yàn)閳?zhí)行異常而結(jié)束,那么線程池會(huì)補(bǔ)充一個(gè)新線程。當(dāng)線程處于空閑狀態(tài)時(shí),他們并不會(huì)被回收,除非線程池被關(guān)閉。當(dāng)所有的線程都處于活動(dòng)狀態(tài)時(shí),新的任務(wù)都會(huì)處于等待狀態(tài),直到有線程空閑出來。
會(huì)存在出現(xiàn)阻塞隊(duì)列堆積大,導(dǎo)致的OOM
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), threadFactory); }
newScheduledThreadPool創(chuàng)建一個(gè)大小無限的線程池,此線程池支持定時(shí)以及周期性執(zhí)行任務(wù)的需求。
線程總數(shù)閾值為Integer.MAX_VALUE,工作隊(duì)列使用DelayedWorkQueue,非核心線程存活時(shí)間為0,所以線程池僅僅包含固定數(shù)目的核心線程。
會(huì)存在出現(xiàn)阻塞隊(duì)列堆積過大,導(dǎo)致的OOM
public static ScheduledExecutorService newScheduledThreadPool( int corePoolSize, ThreadFactory threadFactory) { return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); } public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), threadFactory); }
可以看出來上面的方法一共使用了DelayedWorkQueue、LinkedBlockingQueue和 SynchronousQueue。這個(gè)就是線程核心之一的阻塞隊(duì)列。
scheduleAtFixedRate: 按照固定速率周期執(zhí)行
scheduleWithFixedDelay:上個(gè)任務(wù)延遲固定時(shí)間后執(zhí)行
它一般分為直接提交隊(duì)列、有界任務(wù)隊(duì)列、無界任務(wù)隊(duì)列、優(yōu)先任務(wù)隊(duì)列;
直接提交隊(duì)列:設(shè)置為SynchronousQueue隊(duì)列,SynchronousQueue是一個(gè)特殊的BlockingQueue,它沒有容量,每執(zhí)行一個(gè)插入操作就會(huì)阻塞,需要再執(zhí)行一個(gè)刪除操作才會(huì)被喚醒,反之每一個(gè)刪除操作也都要等待對(duì)應(yīng)的插入操作。
一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列,每個(gè)插入操作,必須等到另一個(gè)線程調(diào)用移除操作,否則插入操作一直處于阻塞狀態(tài)
SynchronousQueue隊(duì)列,提交的任務(wù)不會(huì)被保存,總是會(huì)馬上提交執(zhí)行。如果用于執(zhí)行任務(wù)的線程數(shù)量小于maximumPoolSize,則嘗試創(chuàng)建新的進(jìn)程,如果達(dá)到maximumPoolSize設(shè)置的最大值,則根據(jù)你設(shè)置的handler執(zhí)行拒絕策略。因此這種方式你提交的任務(wù)不會(huì)被緩存起來,而是會(huì)被馬上執(zhí)行,在這種情況下,你需要對(duì)你程序的并發(fā)量有個(gè)準(zhǔn)確的評(píng)估,才能設(shè)置合適的maximumPoolSize數(shù)量,否則很容易就會(huì)執(zhí)行拒絕策略;
有界的任務(wù)隊(duì)列:有界的任務(wù)隊(duì)列可以使用ArrayBlockingQueue實(shí)現(xiàn),如下所示:
new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue(10),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
使用ArrayBlockingQueue有界任務(wù)隊(duì)列,若有新的任務(wù)需要執(zhí)行時(shí),線程池會(huì)創(chuàng)建新的線程,直到創(chuàng)建的線程數(shù)量達(dá)到corePoolSize時(shí),則會(huì)將新的任務(wù)加入到等待隊(duì)列中。若等待隊(duì)列已滿,即超過ArrayBlockingQueue初始化的容量,則繼續(xù)創(chuàng)建線程,直到線程數(shù)量達(dá)到maximumPoolSize設(shè)置的最大線程數(shù)量,若大于maximumPoolSize,則執(zhí)行拒絕策略。
在這種情況下,線程數(shù)量的上限與有界任務(wù)隊(duì)列的狀態(tài)有直接關(guān)系,如果有界隊(duì)列初始容量較大或者沒有達(dá)到超負(fù)荷的狀態(tài),線程數(shù)將一直維持在corePoolSize以下,反之當(dāng)任務(wù)隊(duì)列已滿時(shí),則會(huì)以maximumPoolSize為最大線程數(shù)上限。
無界的任務(wù)隊(duì)列:無界任務(wù)隊(duì)列可以使用LinkedBlockingQueue實(shí)現(xiàn),如下所示:
new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
使用無界任務(wù)隊(duì)列,線程池的任務(wù)隊(duì)列可以無限制的添加新的任務(wù),而線程池創(chuàng)建的最大線程數(shù)量就是你corePoolSize設(shè)置的數(shù)量,也就是說在這種情況下maximumPoolSize這個(gè)參數(shù)是無效的,哪怕你的任務(wù)隊(duì)列中緩存了很多未執(zhí)行的任務(wù),當(dāng)線程池的線程數(shù)達(dá)到corePoolSize后,就不會(huì)再增加了;若后續(xù)有新的任務(wù)加入,則直接進(jìn)入隊(duì)列等待,當(dāng)使用這種任務(wù)隊(duì)列模式時(shí),一定要注意你任務(wù)提交與處理之間的協(xié)調(diào)與控制,不然會(huì)出現(xiàn)隊(duì)列中的任務(wù)由于無法及時(shí)處理導(dǎo)致一直增長(zhǎng),直到最后資源耗盡的問題。
優(yōu)先任務(wù)隊(duì)列:優(yōu)先任務(wù)隊(duì)列通過PriorityBlockingQueue實(shí)現(xiàn),使用平衡二叉樹堆,實(shí)現(xiàn)的具有優(yōu)先級(jí)的無界阻塞隊(duì)列
任務(wù)會(huì)按優(yōu)先級(jí)重新排列執(zhí)行,且線程池的線程數(shù)一直為corePoolSize,也就是只有一個(gè)。
PriorityBlockingQueue其實(shí)是一個(gè)特殊的無界隊(duì)列,它其中無論添加了多少個(gè)任務(wù),線程池創(chuàng)建的線程數(shù)也不會(huì)超過corePoolSize的數(shù)量,只不過其他隊(duì)列一般是按照先進(jìn)先出的規(guī)則處理任務(wù),而PriorityBlockingQueue隊(duì)列可以自定義規(guī)則根據(jù)任務(wù)的優(yōu)先級(jí)順序先后執(zhí)行。
其實(shí)LinkedBlockingQueue也是可以設(shè)置界限的,它默認(rèn)的界限是Integer.MAX_VALUE。同時(shí)也支持也支持構(gòu)造的時(shí)候設(shè)置隊(duì)列大小。
無界阻塞延遲隊(duì)列,隊(duì)列中每個(gè)元素均有過期時(shí)間,當(dāng)從隊(duì)列獲取元素時(shí),只有過期元素才會(huì)出隊(duì)列。隊(duì)列頭元素是最塊要過期的元素。
public interface RejectedExecutionHandler { void rejectedExecution(Runnable r, ThreadPoolExecutor executor); }
當(dāng)Executor已經(jīng)關(guān)閉,即執(zhí)行了executorService.shutdown()方法后,或者Executor將有限邊界用于最大線程和工作隊(duì)列容量,且已經(jīng)飽和時(shí)。使用方法execute()提交的新任務(wù)將被拒絕. 在以上述情況下,execute方法將調(diào)用其RejectedExecutionHandler的rejectExecution()方法
RejectedExecutionHandler.rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor)
也稱為終止策略,遭到拒絕將拋出運(yùn)行時(shí)RejectedExecutionException。業(yè)務(wù)方能通過捕獲異常及時(shí)得到對(duì)本次任務(wù)提交的結(jié)果反饋。
public static class AbortPolicy implements RejectedExecutionHandler { public AbortPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString()); } }
擁有自主反饋控制,讓提交者執(zhí)行提交任務(wù),能夠減緩新任務(wù)的提交速度。這種情況是需要讓所有的任務(wù)都執(zhí)行完畢。
public static class CallerRunsPolicy implements RejectedExecutionHandler { public CallerRunsPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { r.run(); } } }
拒絕任務(wù)的處理程序,靜默丟棄任務(wù)。使用此策略,我們可能無法感知系統(tǒng)的異常狀態(tài)。慎用~!
public static class DiscardPolicy implements RejectedExecutionHandler { public DiscardPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { } }
丟棄隊(duì)列中最前面的任務(wù),然后重新提交被拒絕的任務(wù)。是否要使用此策略需要看業(yè)務(wù)是否需要新老的替換,慎用~!(LRU)
public static class DiscardOldestPolicy implements RejectedExecutionHandler { public DiscardOldestPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { e.getQueue().poll(); e.execute(r); } } }
判斷線程池中核心線程數(shù)是否已達(dá)閾值corePoolSize,若否,則創(chuàng)建一個(gè)新核心線程執(zhí)行任務(wù)
若核心線程數(shù)已達(dá)閾值corePoolSize,判斷阻塞隊(duì)列workQueue是否已滿,若未滿,則將新任務(wù)添加進(jìn)阻塞隊(duì)列
若滿,再判斷,線程池中線程數(shù)是否達(dá)到閾值maximumPoolSize,若否,則新建一個(gè)非核心線程執(zhí)行任務(wù)。若達(dá)到閾值,則執(zhí)行線程池飽和策略。
AbortPolicy:直接拋出一個(gè)異常,默認(rèn)策略
DiscardPolicy: 直接丟棄任務(wù)
DiscardOldestPolicy:拋棄下一個(gè)將要被執(zhí)行的任務(wù)(最舊任務(wù))
CallerRunsPolicy:主線程中執(zhí)行任務(wù)
要想合理的配置線程池,就必須首先分析任務(wù)特性,可以從以下幾個(gè)角度來進(jìn)行分析:
任務(wù)的性質(zhì):CPU密集型任務(wù),IO密集型任務(wù)和混合型任務(wù)。
任務(wù)的優(yōu)先級(jí):高,中和低。
任務(wù)的執(zhí)行時(shí)間:長(zhǎng),中和短。
任務(wù)的依賴性:是否依賴其他系統(tǒng)資源,如數(shù)據(jù)庫(kù)連接。
根據(jù)任務(wù)所需要的cpu和io資源的量可以分為,
CPU密集型任務(wù): 主要是執(zhí)行計(jì)算任務(wù),響應(yīng)時(shí)間很快,cpu一直在運(yùn)行,這種任務(wù)cpu的利用率很高。
IO密集型任務(wù):主要是進(jìn)行IO操作,執(zhí)行IO操作的時(shí)間較長(zhǎng),這是cpu出于空閑狀態(tài),導(dǎo)致cpu的利用率不高。
為了合理最大限度的使用系統(tǒng)資源同時(shí)也要保證的程序的高性能,可以給CPU密集型任務(wù)和IO密集型任務(wù)配置一些線程數(shù)。
CPU密集型:線程個(gè)數(shù)為CPU核數(shù)。這幾個(gè)線程可以并行執(zhí)行,不存在線程切換到開銷,提高了cpu的利用率的同時(shí)也減少了切換線程導(dǎo)致的性能損耗
IO密集型:線程個(gè)數(shù)為CPU核數(shù)的兩倍。到其中的線程在IO操作的時(shí)候,其他線程可以繼續(xù)用cpu,提高了cpu的利用率。
看完上述內(nèi)容,你們掌握J(rèn)ava并發(fā)編程中線程池工作原理的示例分析的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!