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

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-08 16:28:58

web项目启动线程服务的相关文章

Spring Boot构建的Web项目如何在服务端校验表单输入

本文首发于个人网站:Spring Boot构建的Web项目如何在服务端校验表单输入 这个例子用于演示在Spring Boot应用中如何验证Web 应用的输入,我们将会建立一个简单的Spring MVC应用,来读取用户输入并使用validation注解来检查,并且当用户输入错误时,应用需要再屏幕上显示错误信息提示用户重新输入. 首先构建Maven项目,该项目的pom文件内容如下: <?xml version="1.0" encoding="UTF-8"?>

spring配置与Web 项目启动

今天打算学习下spring继承quartz的用法,然后想搭建一个纯净的spring项目用来做相关的实验,虽然只是寥寥几行配置文件,但突然选择性失忆忘了这其中容器加载的过程和配置的意义.复习了下此刻写个随便记录下刚刚的领悟. web.xml配置 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instanc

web项目启动时,执行某个方法

1.监听(Listener) web文件添加 <listener> <listener-class>cn.ro.common.InitListener</listener-class> </listener> 添加InitListener类,如下 package cn.ro.common; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener

java web项目启动加载顺序

web.xml加载过程(步骤):       1.启动WEB项目的时候,容器(如:Tomcat)会去读它的配置文件web.xml.读两个节点: <listener></listener> 和 <context-param></context-param> 2.紧接着,容器创建一个ServletContext(上下文),这个WEB项目所有部分都将共享这个上下文. 3.容器将<context-param></context-param>转

web项目启动时,自动执行代码

tomcat启动时自动执行,以下两种方法的执行时长,会计算在tomcat的启动时长里. 1.ServletContextListener web.xml配置<listener> <listener-class>com.yuan.framework.GreyClientInitListener</listener-class> </listener> 1 public class GreyClientInitListener implements Servle

eclipse 导入web项目后,线程假死

eclipse 导入web项目后,就出现关闭后,线程还存在的情况.使用java mission control 查看发现java script indexing线程在running. 关闭js验证后,线程可以正常关闭. http://www.jb51.net/article/46642.htm 第一步:去除eclipse的JS验证:将windows->preference->Java Script->Validator->Errors/Warnings->Enable Jav

在web项目启动时,执行某个方法

在web项目中有很多时候需要在项目启动时就执行一些方法,而且只需要执行一次,比如:加载解析自定义的配置文件.初始化数据库信息等等,在项目启动时就直接执行一些方法,可以减少很多繁琐的操作. 在工作中遇到了项目初始数据需要跟其他项目同步的问题,也就是说在项目部署后,启动的时候就要同步另外一个项目的数据,这里写了个简单的实例,用的是监听器机制,创建一个类实现ServletContextListener 接口,实现里面的contextInitialized和contextDestroyed方法. pac

在web项目启动时,使用监听器来执行某个方法

在web项目中有很多时候需要在项目启动时就执行一些方法,而且只需要执行一次,比如:加载解析自定义的配置文件.初始化数据库信息等等,在项目启动时就直接执行一些方法,可以减少很多繁琐的操作. 这里写了个简单的实例,用的是监听器机制,创建一个类实现ServletContextListener 接口,实现里面的contextInitialized和contextDestroyed方法. 1 package com.test.listener; 2 3 import javax.servlet.Servl

&lt;Web&gt; 如何给web项目添加redis服务

前言 这两天项目用到redis,而我自己也正准备看这个,所以就从头开始学习了一遍. 既然要用,说明已经对redis是干什么的,特点是什么,对项目有什么好处,需要缓存什么东西等问题都了解过了,所以我们直接开搞: 怎么获取redis 安装redis,linux下wget到github的源码,然后直接make就行了,比较简单. 我是在windows下用的,所以来说下:到从redis官网连接过去的redisServer下载redis-2.8.19.zip,解压之后运行redis-server.exe即可