(記錄一句:用多線程處理和消息隊列來處理大數據量操作,文件操作,或者併發。)
多線程併發處理起來通常比較麻煩,如果你使用spring容器來管理業務bean,事情就好辦了多了。spring封裝了Java的多線程的實現,你只需要關注於併發事物的流程以及一些併發負載量等特性,具體來說如何使用spring來處理併發事務:
1.瞭解 TaskExecutor接口
Spring的TaskExecutor接口等同於java.util.concurrent.Executor接口。 實際上,它存在的主要原因是爲了在使用線程池的時候,將對Java 5的依賴抽象出來。 這個接口只有一個方法execute(Runnable task),它根據線程池的語義和配置,來接受一個執行任務。最初創建TaskExecutor是爲了在需要時給其他Spring組件提供一個線程池的抽象。 例如ApplicationEventMulticaster組件、JMS的 AbstractMessageListenerContainer和對Quartz的整合都使用了TaskExecutor抽象來提供線程池。 當然,如果你的bean需要線程池行爲,你也可以使用這個抽象層。
2. TaskExecutor接口的實現類
(1)SimpleAsyncTaskExecutor 類
這個實現不重用任何線程,或者說它每次調用都啓動一個新線程。但是,它還是支持對併發總數設限,當超過線程併發總數限制時,阻塞新的調用,直到有位置被釋放。如果你需要真正的池,請繼續往下看。
(2)SyncTaskExecutor類
這個實現不會異步執行。相反,每次調用都在發起調用的線程中執行。它的主要用處是在不需要多線程的時候,比如簡單的test case。
(3)ConcurrentTaskExecutor 類
這個實現是對Java 5 java.util.concurrent.Executor類的包裝。有另一個備選, ThreadPoolTaskExecutor類,它暴露了Executor的配置參數作爲bean屬性。很少需要使用ConcurrentTaskExecutor, 但是如果ThreadPoolTaskExecutor不敷所需,ConcurrentTaskExecutor是另外一個備選。
(4)SimpleThreadPoolTaskExecutor 類
這個實現實際上是Quartz的SimpleThreadPool類的子類,它會監聽Spring的生命週期回調。當你有線程池,需要在Quartz和非Quartz組件中共用時,這是它的典型用處。
(5)ThreadPoolTaskExecutor 類
它不支持任何對java.util.concurrent包的替換或者下行移植。Doug Lea和Dawid Kurzyniec對java.util.concurrent的實現都採用了不同的包結構,導致它們無法正確運行。 這個實現只能在Java 5環境中使用,但是卻是這個環境中最常用的。它暴露的bean properties可以用來配置一個java.util.concurrent.ThreadPoolExecutor,把它包裝到一個TaskExecutor中。如果你需要更加先進的類,比如ScheduledThreadPoolExecutor,我們建議你使用ConcurrentTaskExecutor來替代。
(6)TimerTaskExecutor類
這個實現使用一個TimerTask作爲其背後的實現。它和SyncTaskExecutor的不同在於,方法調用是在一個獨立的線程中進行的,雖然在那個線程中是同的。
(7)WorkMana
gerTaskExecutor類
3.文件配置
<!-- modify the parameters of thread pool -->
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!-- 核心線程數 -->
<property name="corePoolSize" value="5"/>
<!-- 最大線程數 -->
<property name="maxPoolSize" value="20"/>
<!-- 隊列最大長度 -->
<property name="queueCapacity" value="10"/>
<!-- 線程池維護線程所允許的空閒時間,默認爲60s -->
<property name="keepAliveSeconds" value="120"/>
</bean>
然後把taskExecutor注入到所需要的類中
<bean id="threadPoolTask" class="cn.springmvc.query.ThreadPoolClass">
<property name="taskExecutor" ref="taskExecutor"></property>
</bean>
就可以在cn.springmvc.query.ThreadPoolClass類中使用線程池了
ThreadPoolTaskExecutor taskExecutor = ThreadPoolClass.getTaskExecutor();
CommentNotification commentNotification = new CommentNotification(tid, userid, commentType, pid, postAuthorId);
taskExecutor.execute(commentNotification);
//其中CommentNotification 如下定義
public static class CommentNotification implements Runnable {
int tid;
int userid;
int commentType;
int pid;
int postAuthorId;
public CommentNotification( int tid, int userid, int commentType, int pid,
int postAuthorId) {
this.tid = tid;
this.userid = userid;
this.commentType = commentType;
this.pid = pid;
this.postAuthorId = postAuthorId;
}
public void run() {
System.out.println("Thread name: " + Thread.currentThread().getName() + " is running");
addCommentNotification(tid, userid, commentType, pid, postAuthorId);
}
}
//其中addCommentNotification方法如下定義
private static void addCommentNotification(final int tid, final int userid, final int commentType, final int pid,
int postAuthorId) {
ForumThread ft = QueryThreadView.getFormThreadInfo(tid);
int authorid = commentType == UserResponse ? postAuthorId : ft.getAuthorid();
System.out.println("addCommentNotification userid : " + userid + " authorid : " + authorid);
//用戶和(文章/評論)作者不是同一人,則添加通知
if (userid != authorid) {
CommonMember commonMember = QueryUserInfo.getCommonMemberInfo(userid);
addResponseNotification(tid, userid, pid, commonMember.getPf_field8(),commonMember.getUsername(), authorid, ft.getSubject(), commentType);
UserNotification.updateNewPrompts(authorid,UserNotification.post, UserNotification.add);
QueryFriend.updateFriendNum(userid, authorid);
}
}