多线程是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); } @Autowired private 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 report bool = httpPush(task); // update message updateStatus(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") @Override public void destroy() { // TODO Auto-generated method stub Iterator<Thread> service = serviceThreadMap.getServiceMap().values().iterator(); while(service.hasNext()){ service.next().stop(); } } /* (non-Javadoc) * @see javax.servlet.GenericServlet#init() */ @Override public void init() throws ServletException { // TODO Auto-generated method stub //super.init(); //得到WebApplicationContext對象 webApp = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); // start send message thread serviceThreadMap = (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启动线程服务了,还是蛮简单的.哈哈,毕竟我也是站在巨人的肩膀上才能完成的
版权声明:本文为博主原创文章,未经博主允许不得转载。