web项目启动线程服务

来源:互联网 发布:mysql索引 编辑:程序博客网 时间:2024/06/07 07:54

         多线程是java入门的必修课程,然而到了接触J2EE时,这份功课就还给了老师了,至少本人是这样的,呵呵.不过等到用到的时候,我还是能想起大概,再加上度娘帮忙,就能重拾回来了,这里我插播一个小故事,是我自身的亲身经历,希望给同道小生有所帮助.以前在做学生的时候,学习java并不是那么用心,有些东西只是知其一不知其二,很多知识点在脑子里有点印象卻不是很深刻,记得有一次我我去一家公司面试,面试官就问我,线程这块,你熟么?作为面试者,谁会说不熟啊,虽然我真的不太熟,但是我当场就回答还行,然后就闹笑话了,面试官问,线程锁有什么用?但是当时我觉得这问题很简单,很激动和紧张的卻一时脑抽了,回答道:为了确保"线性"安全的,然后就没有然后了!线性?.......呃,我还觉得答对的,后来才发觉自己错了,哎....希望大家引以为戒,虽然身为程序员,无需对概念的东西咬文嚼字,但是在别人面前,还是容不得错一丝一毫的犯错,毕竟出来给工作之后,很多细节就决定你的前途!

        好了话不多少,回归正题,今天我想说的是在web项目,也就是在J2EE里运用多线程服务,我也是在项目有需求上才注意到这块上,事前做了比较多的功课,毕竟之前也没用过嘛,特意记下和大家分享自身的做法和想法.这里我说下我的项目环境是ssh的,其他框架也类似啦

        既然是多线程,就少不了主角线程类,主角上场

package com.smartsoft.thread;import java.util.ArrayList;import java.util.List;import net.sf.json.JSONObject;import org.apache.commons.httpclient.HttpClient;import org.apache.commons.httpclient.methods.PostMethod;import org.apache.commons.httpclient.methods.RequestEntity;import org.apache.commons.httpclient.methods.StringRequestEntity;import org.apache.log4j.Logger;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.context.support.SpringBeanAutowiringSupport;import com.google.gson.Gson;import com.smartsoft.common.Constants;import com.smartsoft.model.Gameset;import com.smartsoft.service.GamesetService;import com.smartsoft.task.SocketResultModel;import com.smartsoft.util.SystemConfig;/** * 主线程 *  * */public class NewGameSetThread extends Thread {private Logger logger = Logger.getLogger(NewGameSetThread.class);private List<Gameset> tempList = new ArrayList<Gameset>();private long sleepTime = 3 * 1000;private Gson gson = new Gson();public NewGameSetThread() {SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);}@Autowiredprivate GamesetService gamesetService;public void run() {// 防止多個Thread同時進行數據庫操作造成資源消耗過多try {Thread.currentThread();Thread.sleep(5 * 1000);} catch (InterruptedException e1) {logger.error(e1);}logger.info("NewGameSet Thread Is Started。。。");List<Gameset> standbyList = new ArrayList<Gameset>();// 循环执行任务while (true) {try {boolean bool = false;// 获取消息任务getTask(standbyList);if (!standbyList.isEmpty()) {// 如果待推送的信息集合中有數據for (int i = 0; i < standbyList.size(); i++) {bool = false;try {Gameset task = standbyList.get(i);// Push reportbool = httpPush(task);// update messageupdateStatus(task, bool);} catch (Exception e) {logger.error(e.toString(), e);continue;} finally {try {super.finalize();} catch (Throwable e) {logger.error(e.toString(), e);}}}}standbyList.clear();Thread.sleep(sleepTime);} catch (Exception e) {logger.error(e.toString(), e);continue;}}}private void updateStatus(Gameset task, boolean bool) {if (bool) {task.setPush_status("1");} else {task.setPush_status("0");}gamesetService.update(task);logger.info("NewGameSet Thread Update Push Status id:" + task.getId());}private boolean httpPush(Gameset task) {PushModel pushModel = new PushModel("all", task);String json = gson.toJson(pushModel);logger.info("NewGameSet Thread Push Message: \n" + json);int result = sendHttpRequestToSocketServerWithJson(json);logger.info("NewGameSet Thread id :  " + task.getId() + " Push Result: " + (result == 1 ? "success" : "failure"));return result == 1 ? true : false;}/** * httpClient *  * @param reqStr * @param urlConfig * @param contentType * @return */private static int sendHttpRequest(String reqStr, String urlConfig, String contentType) {try {PostMethod postMethod = new PostMethod(urlConfig);RequestEntity requestEntity = new StringRequestEntity(reqStr, contentType, Constants.CONTENT_ENCODING_UTF8);postMethod.setRequestEntity(requestEntity);HttpClient httpClient = new HttpClient();httpClient.executeMethod(postMethod);SocketResultModel socketResult = (SocketResultModel) JSONObject.toBean(JSONObject.fromObject(postMethod.getResponseBodyAsString()), SocketResultModel.class);Integer httpStatus = socketResult.getCode();return httpStatus == 1 ? 1 : 0;} catch (Exception e) {e.printStackTrace();return 0;}}private static int sendHttpRequestToSocketServerWithJson(String reqStr) {String url = SystemConfig.get("socket.host") + ":" + SystemConfig.get("socket.port");return sendHttpRequest(reqStr, url, Constants.HTTP_CONTENT_TYPE_APPLICATION_JSON);}/** * 获取消息任务 *  * @param standbyList */private void getTask(List<Gameset> standbyList) {// 获取高优先级发送任务tempList = new ArrayList<Gameset>(ThreadVariables.newGameSetList);ThreadVariables.newGameSetList.removeAll(tempList);standbyList.addAll(tempList);// 清空临时列表tempList.clear();}public static void main(String[] args) {Gson gson = new Gson();Gameset task = new Gameset();task.setId(1L);task.setGame_no(8);PushModel pushModel = new PushModel("all", task);String json = gson.toJson(pushModel);System.out.println(json);}}

需求是不定时的去把消息推送到另一台服务器上,但是消息是不确定什么时候来的,来多少的,这种东西就不好用定时器去实现了,只能用线程监听去跑了

业务逻辑很简单,我会在别的地方把消息添加到集合,又线程去不断监听集合里是否有消息,有就立马推送出去,没有就不做任何事情

package com.smartsoft.thread;import java.util.ArrayList;import java.util.Collections;import java.util.List;import com.smartsoft.model.Gameset;public class ThreadVariables {/** * callback 任務列表 */public static List<Gameset> newGameSetList = Collections.synchronizedList(new ArrayList<Gameset>());public static void addnewGameSetList(Gameset gameset){newGameSetList.add(gameset);}}

这个集合当然是要自带线程安全的啦,呵呵

主角已定,当然是剧本啦,我们需要制定主角出场的时间,这里我用到servlet去启动线程,具体如下

package com.smartsoft.thread;import java.util.Map;public class ServiceThreadMap {Map<String, Thread> serviceMap;public ServiceThreadMap(Map<String, Thread> serviceMap) {super();this.serviceMap = serviceMap;}public Map<String, Thread> getServiceMap() {return serviceMap;}}

package com.smartsoft.servlet;import java.util.Iterator;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import org.springframework.web.context.WebApplicationContext;import org.springframework.web.context.support.WebApplicationContextUtils;import com.smartsoft.thread.ServiceThreadMap;/** * 啟用已經註冊的線程 * @author Dan * */public class BootStrapper extends HttpServlet{private static final long serialVersionUID = 1L;private WebApplicationContext webApp;private ServiceThreadMap serviceThreadMap;/* (non-Javadoc) * @see javax.servlet.GenericServlet#destroy() */@SuppressWarnings("deprecation")@Overridepublic void destroy() {// TODO Auto-generated method stubIterator<Thread> service = serviceThreadMap.getServiceMap().values().iterator();while(service.hasNext()){service.next().stop();}}/* (non-Javadoc) * @see javax.servlet.GenericServlet#init() */@Overridepublic void init() throws ServletException {// TODO Auto-generated method stub//super.init();//得到WebApplicationContext對象webApp = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());// start send message threadserviceThreadMap = (ServiceThreadMap) webApp.getBean("serviceMap");//得到service-spring.xml中註冊的線程列表Iterator<Thread> service = serviceThreadMap.getServiceMap().values().iterator();//得到線程列表中的線程迭代器/* * 啟動列表中的每一個線程 */while(service.hasNext()){System.out.println("---------------------------------------------------");service.next().start();}}}

需要注意的是:这里是写成一个map集合,因为可以扩展同时启动多个线程

在spring的xml里注册线程类

<bean id="newGameSetThread" class="com.smartsoft.thread.NewGameSetThread"></bean><!-- 线程注册  --><bean id="serviceMap" class="com.smartsoft.thread.ServiceThreadMap"><constructor-arg index="0"><map><!-- Dan --><entry key="newGameSetThread" value-ref="newGameSetThread"/></map></constructor-arg></bean>

这里只有一个线程类启动,如有多个可以在这里添加

最后在web.xml随项目启动启动servlet

<servlet><servlet-name>bootstrapper</servlet-name><servlet-class>com.smartsoft.servlet.BootStrapper</servlet-class><load-on-startup>1</load-on-startup></servlet>

这样就可以在web启动线程服务了,还是蛮简单的.哈哈,毕竟我也是站在巨人的肩膀上才能完成的



1 0
原创粉丝点击