web项目启动线程服务

         多线程是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启动线程服务了,还是蛮简单的.哈哈,毕竟我也是站在巨人的肩膀上才能完成的



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值