多執行緒併發處理資料的問題

2021-08-31 02:57:39 字數 3815 閱讀 5077

在現在的專案中遇到的乙個問題。

我所做的簡訊平台,原來只是單執行緒傳送簡訊的,但是由於公司的應用範圍的擴大,簡訊的傳送量成倍的增多,一批插入的簡訊量達到5w資料,如果按照以前的方式,傳送過程十分緩慢。因為我們所用的第三方簡訊提供商只提供給我們10個併發的限制,所以我們採用10條執行緒進行讀取。一次發10條,等10條傳送完成以後再傳送另外10條。

以下是程式:

private  void sendsmsloop() throws exception   

string sql =""

+"select top 10"

+"smssend.id "

+",smssend.phonenumber "

+",smssend.content "

+",smssend.subcode  "

+",smssend.clientid  "

+",smssend.sid  "

+"from  "

+"smssend "

+"where "

+"(smssend.handleflag = 0 "

+"and datediff(minute, smssend.registerdate, getdate()) < 30 "

+"and left(smssend.phonenumber,3)  in ('130','131','132','155','156','186','134','135','136','137','138','139','150','151','152','154','157','158','159','187','188'))  or (clientid='1' and senddate is null)";

stmt = dbconn.createstatement();

rs = stmt.executequery(sql);

int inc = 0;

while(rs.next())

//迴圈判斷10個執行緒的flag資訊,判斷flag必須都為true了。才可以進行下一輪掃瞄。【判斷為true的結果就是只要該執行緒執行完畢後flag就賦值為true】

while(true)

}}

if (_flag)else

}

}class smsthread extends thread

public smsthread(string id,string phonenumber,string content,string subcode,string clientid,string sid)

public void run()

catch (exception e)

//每個執行緒執行完成以後都會將自己的flag設定為true,所以我們在迴圈取資料的時候要保證所有的執行緒方法都執行了,才開始下一次的資料讀取。

flag = true;}}

private void sendsmsbystrategy(string id, string phonenumber, string content,string subcode,string clientid,string sid) throws exception

對以上方法的改良版本v1.0。上面程式存在的乙個效能問題就是,每次發完10條資訊都會要重新去資料庫取出一次資料,這樣對效能也會造成一定的影響,現在對齊進行改良,因為我們根據每次併發8條執行緒對於傳送簡訊是最快的【主要是簡訊提供商那邊提供給我們雖然有10 個併發,但是我們自己測試8個併發是最好的,10個併發會有連線異常發生】。我改變讀取策略,一次從資料庫中讀取80條資訊,放在集合中,然後用8個執行緒分別每天處理10條資訊進行傳送,等傳送完畢這80條資訊,然後再去取另外的80條資訊。為什麼不一次性取多點資料呢,因為我們還有其他的資料任務在操作簡訊表,如果資料量一次取太大,會對資料庫造成死鎖,所以取的夠用就可以了。

具體**實現:

private  void sendsmsloop() throws exception

for(int i=0;i

//判斷每開啟8個執行緒就開始等待,等待到該8個執行緒執行完畢,然後將該8個執行緒清空,然後再開啟後面的8個。

if(inc>=10)

else

}該方法比第一種方法的效率要高點,同時也減少了對資料庫的操作。

對以上方法的改良,上一種方式也存在缺點,比如如果有24條資料,第一條執行緒處理8條,第2條處理8條,第三條處理6條,如果第一條執行緒提比後面兩條處理的都快很多,那麼先處理完成的執行緒將被浪費,我們可以採用執行緒池的概念。

與資料庫連線池類似的是,執行緒池會啟動大量的空閒執行緒,程式將乙個runnable物件的執行緒給執行緒池,執行緒池就會啟動一挑執行緒來執行該物件的run方法,當run方法執行結束後,該執行緒不會死亡,而是再次返回執行緒池中成為空閒狀態,等待執行下乙個runable物件的run方法。

jdk1.5提供了乙個executors工廠類來產生執行緒池,該工廠類包含如下幾個靜態工廠方法來建立執行緒池:

2.newfixedthreadpool(int n):建立乙個可重用的具有固定執行緒數的執行緒池。

3.newsinglethreadexecutor():建立乙個只有單執行緒的執行緒池,他相當於newfixedthreadpool方法時傳入引數為1

5.newsinglethreadscheduledexecutor()建立乙個只有一條執行緒的執行緒池,它可以再制定延遲後執行執行緒任務。

以上5個方法前三個返回乙個 executorservice物件,該物件代表乙個執行緒池,他可以執行runnable物件或callable物件所代表的執行緒。

executorservice代表盡快執行執行緒的執行緒池(只要執行緒池中有空閒執行緒立即執行執行緒任務),程式只要將乙個runnable或callable物件提交給執行緒池即可,該執行緒池就會盡快執行該任務。他提供了三個方法:

1. future<?> submit(runnable task):將乙個runnable物件提交給指定的執行緒池,執行緒池將在有空閒執行緒時執行物件所代表的任務,其中future物件代表runnable人物的返回值,但run方法沒有返回值,所以future物件將在run方法執行結束後返回null,但可以呼叫future的isdone(),iscancelled()方法獲得 runnable物件的執行狀態。

2.futuresubmit(runnable task,t result):將乙個runnable物件提交給指定的執行緒池,執行緒池將在空閒執行緒時候執行物件的任務,result顯示指定執行緒執行結束後的返回值,所以future物件將在run方法執行結束後返回result。

3.futuresubmit(callabletask):將乙個callable物件提交給指定的執行緒池,執行緒池將在空閒執行緒時候執行物件的任務,future代表將在run方法執行結束後返回值。

**:首先開啟具有8個固定執行緒的執行緒池。

public executorservice pool = executors.newfixedthreadpool(8);

private  void sendsmsloop() throws exception

for(int i=0;i

//開啟乙個執行緒,並將該執行緒放入到執行緒池中,然後將該執行緒的返回值放入到乙個list的結合中,用來儲存所開啟執行緒的返回結果。

if(inc>=10)

else

}用了執行緒池以後,如果一次取80條資料,原來每次要用8個執行緒來發,但是執行緒池每次也許只用5-6個就可以用來傳送8條資訊了。因為有可能第乙個用完的執行緒在傳送第7條資訊的時候又被拿出來用。

多執行緒併發快速處理資料

import j a.util.arraylist import j a.util.list import j a.util.concurrent.callable import j a.util.concurrent.executionexception import j a.util.concu...

多執行緒併發問題

執行緒安全是乙個非常燙手的山芋,因為即使合理運用了鎖,也不一定能保證執行緒安全,這是因為落後的編譯器無法滿足日益增長的併發需求,很多看似無錯的 在優化和併發面前產生了麻煩,可以看下面的 x 0 thread1 thread2 lock lock x x unlock unlock 上面的 看著是沒有...

多執行緒的併發問題?

1 描述 在乙個cpu上同時執行多個執行緒時,會存在多個執行緒競爭cpu資源的問題,但是有時候一段 是不允許打斷,或是出現死鎖的狀態。死鎖 多個執行緒出現了鎖巢狀,形成資源互相等待的狀態,使程式無法繼續執行。2 解決或避免死鎖狀態的方法 引入鎖物件 synchronized 同步 塊 在需要遵循原子...