亚洲精品中文免费|亚洲日韩中文字幕制服|久久精品亚洲免费|一本之道久久免费

      
      

            <dl id="hur0q"><div id="hur0q"></div></dl>

                「高并發(fā)」這樣理解線程池中Worker線程的執(zhí)行流程才正確

                Worker類分析

                Worker類從類的結(jié)構(gòu)上來(lái)看,繼承了AQS(AbstractQueuedSynchronizer類)并實(shí)現(xiàn)了Runnable接口。本質(zhì)上,Worker類既是一個(gè)同步組件,也是一個(gè)執(zhí)行任務(wù)的線程。接下來(lái),我們看下Worker類的源碼,如下所示。

                private final class Worker extends AbstractQueuedSynchronizer implements Runnable {private static final long serialVersionUID = 6138294804551838833L;//執(zhí)行任務(wù)的線程類final Thread thread;//初始化執(zhí)行的任務(wù),第一次執(zhí)行的任務(wù)Runnable firstTask;//完成任務(wù)的計(jì)數(shù)volatile long completedTasks;//Worker類的構(gòu)造方法,初始化任務(wù)并調(diào)用線程工廠創(chuàng)建執(zhí)行任務(wù)的線程Worker(Runnable firstTask) {setState(-1); this.firstTask = firstTask;this.thread = getThreadFactory().newThread(this);}//重寫Runnable接口的run()方法public void run() {//調(diào)用ThreadPoolExecutor類的runWorker(Worker)方法runWorker(this);}//檢測(cè)是否是否獲取到鎖//state=0表示未獲取到鎖//state=1表示已獲取到鎖protected boolean isHeldExclusively() {return getState() != 0;}//使用AQS設(shè)置線程狀態(tài)protected boolean tryAcquire(int unused) {if (compareAndSetState(0, 1)) {setExclusiveOwnerThread(Thread.currentThread());return true;}return false;}//嘗試釋放鎖protected boolean tryRelease(int unused) {setExclusiveOwnerThread(null);setState(0);return true;}public void lock() { acquire(1); }public boolean tryLock() { return tryAcquire(1); }public void unlock() { release(1); }public boolean isLocked() { return isHeldExclusively(); }void interruptIfStarted() {Thread t;if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {try {t.interrupt();} catch (SecurityException ignore) {}}}}復(fù)制代碼

                在Worker類的構(gòu)造方法中,可以看出,首先將同步狀態(tài)state設(shè)置為-1,設(shè)置為-1是為了防止runWorker方法運(yùn)行之前被中斷。這是因?yàn)槿绻渌€程調(diào)用線程池的shutdownNow()方法時(shí),如果Worker類中的state狀態(tài)的值大于0,則會(huì)中斷線程,如果state狀態(tài)的值為-1,則不會(huì)中斷線程。

                Worker類實(shí)現(xiàn)了Runnable接口,需要重寫run方法,而Worker的run方法本質(zhì)上調(diào)用的是ThreadPoolExecutor類的runWorker方法,在runWorker方法中,會(huì)首先調(diào)用unlock方法,該方法會(huì)將state置為0,所以這個(gè)時(shí)候調(diào)用shutDownNow方法就會(huì)中斷當(dāng)前線程,而這個(gè)時(shí)候已經(jīng)進(jìn)入了runWork方法,就不會(huì)在還沒(méi)有執(zhí)行runWorker方法的時(shí)候就中斷線程。

                注意:大家需要重點(diǎn)理解Worker類的實(shí)現(xiàn)。

                Worker類中調(diào)用了ThreadPoolExecutor類的runWorker(Worker)方法。接下來(lái),我們一起看下ThreadPoolExecutor類的runWorker(Worker)方法的實(shí)現(xiàn)。

                runWorker(Worker)方法

                首先,我們看下RunWorker(Worker)方法的源碼,如下所示。

                final void runWorker(Worker w) {Thread wt = Thread.currentThread();Runnable task = w.firstTask;w.firstTask = null;//釋放鎖,將state設(shè)置為0,允許中斷任務(wù)的執(zhí)行w.unlock();boolean completedAbruptly = true;try {//如果任務(wù)不為空,或者從任務(wù)隊(duì)列中獲取的任務(wù)不為空,則執(zhí)行while循環(huán)while (task != null || (task = getTask()) != null) {//如果任務(wù)不為空,則獲取Worker工作線程的獨(dú)占鎖w.lock();//如果線程已經(jīng)停止,或者中斷線程后線程終止并且沒(méi)有成功中斷線程//大家好好理解下這個(gè)邏輯if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) &&!wt.isInterrupted())//中斷線程wt.interrupt();try {//執(zhí)行任務(wù)前執(zhí)行的邏輯beforeExecute(wt, task);Throwable thrown = null;try {//調(diào)用Runable接口的run方法執(zhí)行任務(wù)task.run();} catch (RuntimeException x) {thrown = x; throw x;} catch (Error x) {thrown = x; throw x;} catch (Throwable x) {thrown = x; throw new Error(x);} finally {//執(zhí)行任務(wù)后執(zhí)行的邏輯afterExecute(task, thrown);}} finally {//任務(wù)執(zhí)行完成后,將其設(shè)置為空task = null;//完成的任務(wù)數(shù)量加1w.completedTasks++;//釋放工作線程獲得的鎖w.unlock();}}completedAbruptly = false;} finally {//執(zhí)行退出Worker線程的邏輯processWorkerExit(w, completedAbruptly);}}復(fù)制代碼

                這里,我們拆解runWorker(Worker)方法。

                (1)獲取當(dāng)前線程的句柄和工作線程中的任務(wù),并將工作線程中的任務(wù)設(shè)置為空,執(zhí)行unlock方法釋放鎖,將state狀態(tài)設(shè)置為0,此時(shí)可以中斷工作線程,代碼如下所示。

                Thread wt = Thread.currentThread();Runnable task = w.firstTask;w.firstTask = null;//釋放鎖,將state設(shè)置為0,允許中斷任務(wù)的執(zhí)行w.unlock();復(fù)制代碼

                (2)在while循環(huán)中進(jìn)行判斷,如果任務(wù)不為空,或者從任務(wù)隊(duì)列中獲取的任務(wù)不為空,則執(zhí)行while循環(huán),否則,調(diào)用processWorkerExit(Worker, boolean)方法退出Worker工作線程。

                while (task != null || (task = getTask()) != null)復(fù)制代碼

                (3)如果滿足while的循環(huán)條件,首先獲取工作線程內(nèi)部的獨(dú)占鎖,并執(zhí)行一系列的邏輯判斷來(lái)檢測(cè)是否需要中斷當(dāng)前線程的執(zhí)行,代碼如下所示。

                //如果任務(wù)不為空,則獲取Worker工作線程的獨(dú)占鎖w.lock();//如果線程已經(jīng)停止,或者中斷線程后線程終止并且沒(méi)有成功中斷線程//大家好好理解下這個(gè)邏輯if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) &&!wt.isInterrupted())//中斷線程wt.interrupt();復(fù)制代碼

                (4)調(diào)用執(zhí)行任務(wù)前執(zhí)行的邏輯,如下所示

                //執(zhí)行任務(wù)前執(zhí)行的邏輯beforeExecute(wt, task);復(fù)制代碼

                (5)調(diào)用Runable接口的run方法執(zhí)行任務(wù)

                //調(diào)用Runable接口的run方法執(zhí)行任務(wù)task.run();復(fù)制代碼

                (6)調(diào)用執(zhí)行任務(wù)后執(zhí)行的邏輯

                //執(zhí)行任務(wù)后執(zhí)行的邏輯afterExecute(task, thrown);復(fù)制代碼

                (7)將完成的任務(wù)設(shè)置為空,完成的任務(wù)數(shù)量加1并釋放工作線程的鎖。

                //任務(wù)執(zhí)行完成后,將其設(shè)置為空task = null;//完成的任務(wù)數(shù)量加1w.completedTasks++;//釋放工作線程獲得的鎖w.unlock();復(fù)制代碼

                (8)退出Worker線程的執(zhí)行,如下所示

                //執(zhí)行退出Worker線程的邏輯processWorkerExit(w, completedAbruptly);復(fù)制代碼

                從代碼分析上可以看到,當(dāng)從Worker線程中獲取的任務(wù)為空時(shí),會(huì)調(diào)用getTask()方法從任務(wù)隊(duì)列中獲取任務(wù),接下來(lái),我們看下getTask()方法的實(shí)現(xiàn)。

                getTask()方法

                我們先來(lái)看下getTask()方法的源代碼,如下所示。

                private Runnable getTask() {//輪詢是否超時(shí)的標(biāo)識(shí)boolean timedOut = false;//自旋for循環(huán)for (;;) {//獲取ctlint c = ctl.get();//獲取線程池的狀態(tài)int rs = runStateOf(c);//檢測(cè)任務(wù)隊(duì)列是否在線程池停止或關(guān)閉的時(shí)候?yàn)榭?/也就是說(shuō)任務(wù)隊(duì)列是否在線程池未正常運(yùn)行時(shí)為空if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {//減少Worker線程的數(shù)量decrementWorkerCount();return null;}//獲取線程池中線程的數(shù)量int wc = workerCountOf(c);//檢測(cè)當(dāng)前線程池中的線程數(shù)量是否大于corePoolSize的值或者是否正在等待執(zhí)行任務(wù)boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;//如果線程池中的線程數(shù)量大于corePoolSize//獲取大于corePoolSize或者是否正在等待執(zhí)行任務(wù)并且輪詢超時(shí)//并且當(dāng)前線程池中的線程數(shù)量大于1或者任務(wù)隊(duì)列為空if ((wc > maximumPoolSize || (timed && timedOut))&& (wc > 1 || workQueue.isEmpty())) {//成功減少線程池中的工作線程數(shù)量if (compareAndDecrementWorkerCount(c))return null;continue;}try {//從任務(wù)隊(duì)列中獲取任務(wù)Runnable r = timed ?workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :workQueue.take();//任務(wù)不為空直接返回任務(wù)if (r != null)return r;timedOut = true;} catch (InterruptedException retry) {timedOut = false;}}}復(fù)制代碼

                getTask()方法的邏輯比較簡(jiǎn)單,大家看源碼就可以了,我這里就不重復(fù)描述了。

                接下來(lái),我們看下在正式調(diào)用Runnable的run()方法前后,執(zhí)行的beforeExecute方法和afterExecute方法。

                beforeExecute(Thread, Runnable)方法

                beforeExecute(Thread, Runnable)方法的源代碼如下所示。

                protected void beforeExecute(Thread t, Runnable r) { }復(fù)制代碼

                可以看到,beforeExecute(Thread, Runnable)方法的方法體為空,我們可以創(chuàng)建ThreadPoolExecutor的子類來(lái)重寫beforeExecute(Thread, Runnable)方法,使得線程池正式執(zhí)行任務(wù)之前,執(zhí)行我們自己定義的業(yè)務(wù)邏輯。

                afterExecute(Runnable, Throwable)方法

                afterExecute(Runnable, Throwable)方法的源代碼如下所示。

                protected void afterExecute(Runnable r, Throwable t) { }復(fù)制代碼

                可以看到,afterExecute(Runnable, Throwable)方法的方法體同樣為空,我們可以創(chuàng)建ThreadPoolExecutor的子類來(lái)重寫afterExecute(Runnable, Throwable)方法,使得線程池在執(zhí)行任務(wù)之后執(zhí)行我們自己定義的業(yè)務(wù)邏輯。

                接下來(lái),就是退出工作線程的processWorkerExit(Worker, boolean)方法。

                processWorkerExit(Worker, boolean)方法

                processWorkerExit(Worker, boolean)方法的邏輯主要是執(zhí)行退出Worker線程,并且對(duì)一些資源進(jìn)行清理,源代碼如下所示。

                private void processWorkerExit(Worker w, boolean completedAbruptly) {//執(zhí)行過(guò)程中出現(xiàn)了異常,突然中斷if (completedAbruptly)//將工作線程的數(shù)量減1decrementWorkerCount();//獲取全局鎖final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {//累加完成的任務(wù)數(shù)量completedTaskCount += w.completedTasks;//將完成的任務(wù)從workers集合中移除workers.remove(w);} finally {//釋放鎖mainLock.unlock();}//嘗試終止工作線程的執(zhí)行tryTerminate();//獲取ctlint c = ctl.get();//判斷當(dāng)前線程池的狀態(tài)是否小于STOP(RUNNING或者SHUTDOWN)if (runStateLessThan(c, STOP)) {//如果沒(méi)有突然中斷完成if (!completedAbruptly) {//如果allowCoreThreadTimeOut為true,為min賦值為0,否則賦值為corePoolSizeint min = allowCoreThreadTimeOut ? 0 : corePoolSize;//如果min為0并且工作隊(duì)列不為空if (min == 0 && ! workQueue.isEmpty())//min的值設(shè)置為1min = 1;//如果線程池中的線程數(shù)量大于min的值if (workerCountOf(c) >= min)//返回,不再執(zhí)行程序return; }//調(diào)用addWorker方法addWorker(null, false);}}復(fù)制代碼

                接下來(lái),我們拆解processWorkerExit(Worker, boolean)方法。

                (1)執(zhí)行過(guò)程中出現(xiàn)了異常,突然中斷執(zhí)行,則將工作線程數(shù)量減1,如下所示。

                //執(zhí)行過(guò)程中出現(xiàn)了異常,突然中斷if (completedAbruptly)//將工作線程的數(shù)量減1decrementWorkerCount();復(fù)制代碼

                (2)獲取鎖累加完成的任務(wù)數(shù)量,并將完成的任務(wù)從workers集合中移除,并釋放,如下所示。

                //獲取全局鎖final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {//累加完成的任務(wù)數(shù)量completedTaskCount += w.completedTasks;//將完成的任務(wù)從workers集合中移除workers.remove(w);} finally {//釋放鎖mainLock.unlock();}復(fù)制代碼

                (3)嘗試終止工作線程的執(zhí)行

                //嘗試終止工作線程的執(zhí)行tryTerminate();復(fù)制代碼

                (4)處判斷當(dāng)前線程池中的線程個(gè)數(shù)是否小于核心線程數(shù),如果是,需要新增一個(gè)線程保證有足夠的線程可以執(zhí)行任務(wù)隊(duì)列中的任務(wù)或者提交的任務(wù)。

                //獲取ctlint c = ctl.get();//判斷當(dāng)前線程池的狀態(tài)是否小于STOP(RUNNING或者SHUTDOWN)if (runStateLessThan(c, STOP)) {//如果沒(méi)有突然中斷完成if (!completedAbruptly) {//如果allowCoreThreadTimeOut為true,為min賦值為0,否則賦值為corePoolSizeint min = allowCoreThreadTimeOut ? 0 : corePoolSize;//如果min為0并且工作隊(duì)列不為空if (min == 0 && ! workQueue.isEmpty())//min的值設(shè)置為1min = 1;//如果線程池中的線程數(shù)量大于min的值if (workerCountOf(c) >= min)//返回,不再執(zhí)行程序return; }//調(diào)用addWorker方法addWorker(null, false);}復(fù)制代碼

                接下來(lái),我們看下tryTerminate()方法。

                tryTerminate()方法

                tryTerminate()方法的源代碼如下所示。

                final void tryTerminate() {//自旋for循環(huán)for (;;) {//獲取ctlint c = ctl.get();//如果線程池的狀態(tài)為RUNNING//或者狀態(tài)大于TIDYING//或者狀態(tài)為SHUTDOWN并且任務(wù)隊(duì)列為空//直接返回程序,不再執(zhí)行后續(xù)邏輯if (isRunning(c) ||runStateAtLeast(c, TIDYING) ||(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))return;//如果當(dāng)前線程池中的線程數(shù)量不等于0if (workerCountOf(c) != 0) { //中斷線程的執(zhí)行interruptIdleWorkers(ONLY_ONE);return;}//獲取線程池的全局鎖final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {//通過(guò)CAS將線程池的狀態(tài)設(shè)置為TIDYINGif (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {try {//調(diào)用terminated()方法terminated();} finally {//將線程池狀態(tài)設(shè)置為TERMINATEDctl.set(ctlOf(TERMINATED, 0));//喚醒所有因?yàn)檎{(diào)用線程池的awaitTermination方法而被阻塞的線程termination.signalAll();}return;}} finally {//釋放鎖mainLock.unlock();}}}復(fù)制代碼

                (1)獲取ctl,根據(jù)情況設(shè)置線程池狀態(tài)或者中斷線程的執(zhí)行,并返回。

                //獲取ctlint c = ctl.get();//如果線程池的狀態(tài)為RUNNING//或者狀態(tài)大于TIDYING//或者狀態(tài)為SHUTDOWN并且任務(wù)隊(duì)列為空//直接返回程序,不再執(zhí)行后續(xù)邏輯if (isRunning(c) ||runStateAtLeast(c, TIDYING) ||(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))return;//如果當(dāng)前線程池中的線程數(shù)量不等于0if (workerCountOf(c) != 0) { //中斷線程的執(zhí)行interruptIdleWorkers(ONLY_ONE);return;}復(fù)制代碼

                (2)獲取全局鎖,通過(guò)CAS設(shè)置線程池的狀態(tài),調(diào)用terminated()方法執(zhí)行邏輯,最終將線程池的狀態(tài)設(shè)置為TERMINATED,喚醒所有因?yàn)檎{(diào)用線程池的awaitTermination方法而被阻塞的線程,最終釋放鎖,如下所示。

                //獲取線程池的全局final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {//通過(guò)CAS將線程池的狀態(tài)設(shè)置為TIDYINGif (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {try {//調(diào)用terminated()方法terminated();} finally {//將線程池狀態(tài)設(shè)置為TERMINATEDctl.set(ctlOf(TERMINATED, 0));//喚醒所有因?yàn)檎{(diào)用線程池的awaitTermination方法而被阻塞的線程termination.signalAll();}return;}} finally {//釋放鎖mainLock.unlock();}復(fù)制代碼

                接下來(lái),看下terminated()方法。

                terminated()方法

                terminated()方法的源代碼如下所示。

                protected void terminated() { }復(fù)制代碼

                可以看到,terminated()方法的方法體為空,我們可以創(chuàng)建ThreadPoolExecutor的子類來(lái)重寫terminated()方法,值得Worker線程調(diào)用tryTerminate()方法時(shí)執(zhí)行我們自己定義的terminated()方法的業(yè)務(wù)邏輯。

                鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場(chǎng),版權(quán)歸原作者所有,如有侵權(quán)請(qǐng)聯(lián)系管理員(admin#wlmqw.com)刪除。
                用戶投稿
                上一篇 2022年8月20日 09:08
                下一篇 2022年8月20日 09:08

                相關(guān)推薦

                • 分享4條發(fā)微商朋友圈的方法(微商朋友圈應(yīng)該怎么發(fā))

                  對(duì)于微商朋友來(lái)說(shuō),朋友圈的重要性不言而喻了。 那么微商的朋友圈到底該怎么發(fā)呢? 為什么同樣是經(jīng)營(yíng)一個(gè)朋友圈,有的微商看起來(lái)逼格滿滿,實(shí)際效果也不錯(cuò);而有的卻動(dòng)都不動(dòng)就被屏蔽甚至拉黑…

                  2022年11月27日
                • 妻子發(fā)微信:“我老公不在,快來(lái)”,同事:“下了班就來(lái)找你”

                  在現(xiàn)如今網(wǎng)絡(luò)如此發(fā)達(dá)的時(shí)代,大家可以從各個(gè)地方了解到全國(guó)大事小事,正所謂世界之大無(wú)奇不有,每天都發(fā)生著奇奇怪怪的事情,今天小編突然看到這樣一件事,看完之后都不知道說(shuō)什么好了。 王某…

                  2022年11月26日
                • 《寶可夢(mèng)朱紫》夢(mèng)特性怎么獲得?隱藏特性獲取方法推薦

                  寶可夢(mèng)朱紫里有很多寶可夢(mèng)都是擁有夢(mèng)特性會(huì)變強(qiáng)的寶可夢(mèng),很多玩家不知道夢(mèng)特性怎么獲得,下面就給大家?guī)?lái)寶可夢(mèng)朱紫隱藏特性獲取方法推薦,感興趣的小伙伴一起來(lái)看看吧,希望能幫助到大家。 …

                  2022年11月25日
                • 《寶可夢(mèng)朱紫》奇魯莉安怎么進(jìn)化?奇魯莉安進(jìn)化方法分享

                  寶可夢(mèng)朱紫中的奇魯莉安要怎么進(jìn)化呢?很多玩家都不知道,下面就給大家?guī)?lái)寶可夢(mèng)朱紫奇魯莉安進(jìn)化方法分享,感興趣的小伙伴一起來(lái)看看吧,希望能幫助到大家。 奇魯莉安進(jìn)化方法分享 奇魯莉安…

                  2022年11月25日
                • 《樂(lè)隊(duì)的海邊》第二場(chǎng)live秀開(kāi)啟 趙夢(mèng)為鄭秀妍寫中文歌詞

                  今日(11月25日),芒果TV女性經(jīng)營(yíng)勵(lì)志奮斗真人秀《樂(lè)隊(duì)的海邊》第二期即將上線。張儷、趙夢(mèng)、鄭秀妍、于文文、劉戀、張?zhí)鞇?ài)在海南省瓊海市經(jīng)營(yíng)的“炸廚”音樂(lè)餐廳蒸蒸日上,收獲顧客滿滿…

                  2022年11月25日
                • 自由的工作

                  02我國(guó)把自由職業(yè)者分為三類第一類是小本生意人,如個(gè)體零售店小餐館印刷店裝修公司老板,還有路邊小攤經(jīng)營(yíng)者第二類是沒(méi)有底薪的推銷員,如買保險(xiǎn)的人地產(chǎn)經(jīng)紀(jì)房子中介直銷人士,賣卡的人。 …

                  2022年11月25日
                • 客服的崗位職責(zé)怎么寫(客服工作內(nèi)容及職責(zé))

                  各位小伙伴們大家周一好,又到了每周一給大家分享干貨內(nèi)容的時(shí)候啦~ 本期來(lái)跟大家分享一下客服工作管理流程以及客服崗位里面的每項(xiàng)職能崗位的核心細(xì)則,也是干貨滿滿推薦收藏~ 一.補(bǔ)償流程…

                  2022年11月25日
                • cpu性能天梯圖2022 AMD CPU天梯圖最新排行榜出爐

                  用戶在DIY自己的主機(jī)時(shí)選擇CPU是非常關(guān)鍵的,CPU可以說(shuō)是電腦的大腦,大家也都想追求好一點(diǎn)的CPU來(lái)使用,但型號(hào)太多了,大部分的用戶都不知道目前哪一款CPU比較好用,快來(lái)看看詳…

                  2022年11月24日
                • 本人由于個(gè)人原因辭職30字(最簡(jiǎn)單的個(gè)人辭職原因)

                  做人留一線,日后好相見(jiàn)!我們不斷地被職場(chǎng)潛規(guī)則著,同時(shí)也在制造一些潛規(guī)則,每一個(gè)離職理由的背后都有一段難以言說(shuō)的辛酸!離職的時(shí)候如果不想說(shuō)明真實(shí)原因,究竟該怎么說(shuō)合適呢?1、 想讀…

                  2022年11月24日
                • 《寶可夢(mèng)朱紫》暴飛龍?jiān)趺醋??暴飛龍獲得方法

                  寶可夢(mèng)朱紫暴飛龍位置在哪?在游戲中,很多玩家還不清楚暴飛龍具體要怎么樣獲得,其實(shí)獲得方法很簡(jiǎn)單,暴飛龍直接是沒(méi)得抓的,需要玩家從寶貝龍進(jìn)化得到,下面一起來(lái)看一下寶可夢(mèng)朱紫暴飛龍獲得…

                  2022年11月23日

                聯(lián)系我們

                聯(lián)系郵箱:admin#wlmqw.com
                工作時(shí)間:周一至周五,10:30-18:30,節(jié)假日休息