在現在的專案中遇到的乙個問題。
我所做的簡訊平台,原來只是單執行緒傳送簡訊的,但是由於公司的應用範圍的擴大,簡訊的傳送量成倍的增多,一批插入的簡訊量達到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 同步 塊 在需要遵循原子...