分类 Java 下的文章

Servlet的多线程安全问题

public class MyServlet extends HttpServlet {
		final static int i = 0;
		public void doGet(HttpServletRequest req, HttpServletResponse res) {
			private HttpSession session = req.getSession();
			private ServletContext ctx = getServletContext();
			synchronized (ctx) {
				Object obj = ctx.getAttribute();
				// code to alter obj
			}
		}
	}

上面代码中的哪些变量是线程安全的?
选择:
* A. i
* B. session
* C. ctx
* D. req
* E. obj
* F. res
IBM 给出的答案是:
正确答案:
* A、C、D 和 F
说明:
静态变量 i 是线程安全的,因为它是 final(不能被修改),否则它将不是安全的。请求和响应对象的作用域只在请求的生命周期,因此它们也是线程安全的。会话和 ServletContext 对象可以从多个线程访问,同时处理多个请求,因此它们不是线程安全的。但在本例中,同步了 ServletContext 对象,因此它只能由一个线程一次访问。obj 不是线程安全的,因为即使同步了 ServletContext 对象,它的属性也没有同步。它们需要另外进行同步。因此,选项 B 和 E 是不正确的,而选项 A、C、D 和 F 是正确的。
Servlets的多线程安全
多线程占用资源少,处理速度快,提高了效率。
一些编码建议:
对变量和方法定义适当的访问方式, 例如单纯取值操作不会有多线程安全问题;
同步化所有访问重要数据的实例变量; 多线程下,如果操作的是一个变量,且兼有读写操作,
就要考虑加上同步,但同步不能乱加,否则会造成死锁问题。
并发需要注意的
并发的环境:资源处于一个并发的环境
共享资源:多个线程共享一个临界资源
全面同步:如有n个变量访问同一个资源,这n个变量都得同步。即多个锁一把钥匙,钥匙放在一个共享区域内
sychronized(this):粗粒度的锁。是将所有的路都加锁;
sychronized(object o1):细粒度的锁。只对对象中的变量加锁。效率较前面的高,但是较难控制。
读写需要互斥。
sychronized(this):this不能是基本数据类型,必须是Object.不锁对象的引用,而是对象的内存空间。
servlet中需要同步的:成员变量、文件、静态变量、数据库连接
一,servlet容器如何同时处理多个请求。
Servlet采用多线程来处理多个请求同时访问,Servlet容器维护了一个线程池来服务请求。
线程池实际上是等待执行处理的一组线程,也叫做工作者线程(Worker Thread),
Servlet容器使用一个调度线程来管理工作者线程(Dispatcher Thread)。
当容器收到一个访问Servlet的请求,调度者线程从线程池中选出一个工作者线程,将请求传递给该线程,
然后由该线程来执行Servlet的service方法。
当这个线程正在执行的时候,容器收到另外一个请求,调度者线程将从池中选出另外一个工作者线程来服务新的请求;
容器并不关心这个请求是否访问的是同一个Servlet还是另外一个Servlet;
当容器同时收到对同一Servlet的多个请求,那这个Servlet的service方法将以多线程方式并发执行。
二,Servlet容器默认采用单实例多线程的方式来处理请求,减少产生Servlet实例的开销,提升了对请求的响应。
对于Tomcat可以在server.xml中通过元素设置线程池中线程的数目。
就实现来说:
调度者线程类所担负的责任是调度线程,只需要利用自己的属性完成自己的责任。
而其他对象又依赖于该对象所承担的责任,需要得到该特定对象,那该类就是一个单例模式的实现了。
三,如何开发线程安全的Servlet
1,变量的线程安全:这里的变量指字段和共享数据(如表单参数值)。
a,将参数变量本地化:多线程并不共享局部变量.所以我们要尽可能的在servlet中使用局部变量。
例如:String user = request.getParameter(“user”);
b,使用同步块Synchronized,防止可能异步调用的代码块。这意味着线程需要队列处理。
在使用同板块的时候要尽可能的缩小同步代码的范围,不要直接在sevice方法和响应方法上使用同步,这样会严重影响性能。
2,属性的线程安全分析:ServletContext,HttpSession,ServletRequest对象的属性
ServletContext:(线程是不安全的)
ServletContext是可以多线程同时读/写属性的,线程是不安全的。要对属性的读写进行同步处理或者进行深度Clone()。
所以在Servlet上下文中尽可能少地保存频繁改写的数据,可以采取其他方式在多个Servlet中共享,比方我们可以使用单例模式来处理共享数据。
HttpSession:(线程是不安全的)
HttpSession对象在用户会话期存在,只能处理属于同一个Session的请求的线程,因此Session对象的属性访问理论上是线程安全的。
当用户打开多个同属于一个进程的浏览器窗口,在这些窗口的访问属于同一个Session,会出现多次请求,需要多个工作线程来处理请求,可能造成同时多线程读写属性,这时我们对属性的读写进行同步处理。
ServletRequest:(线程是安全的)
对于每一个请求,由一个工作线程来执行,都会创建有一个新的ServletRequest对象,所以ServletRequest对象只能在一个线程中被访问。ServletRequest是线程安全的。
注意:ServletRequest对象在service方法的范围内是有效的,不要试图在service方法结束后仍然保存请求对象的引用。
3,使用同步的集合类:
使用Vector代替ArrayList,使用Hashtable代替HashMap。
4,不要在Servlet中创建自己的线程来完成某个功能:
Servlet本身就是多线程的,在Servlet中再创建线程,将导致执行情况复杂化,出现安全问题。
5,在多个servlet中,对外部对象(例如文件)进行修改操作一定要加锁,做到互斥的访问
四,SingleThreadModel接口
javax.servlet.SingleThreadModel接口是一个标识接口,如果一个Servlet实现了这个接口,
则Servlet容器将保证在同时刻仅有一个线程可以在该servlet实例的service方法中执行,将其他所有请求进行排队。
服务器可以使用多个实例来处理请求,代替单个实例的请求排队带来的性能问题。
服务器可创建一个Servlet类的多个实例组成的实例池,对于每个请求分配Servlet实例进行响应,之后放回到实例池中等待下此请求。此时,局部变量(字段)也是安全的,但对于全局变量和共享数据是不安全的,需要进行同步处理。
而对于这种多实例的情况,使用SingleThreadModel接口并不能解决并发访问产生的问题,
且SingleThreadModel接口在servlet规范中已经被明确声明为deprecated了。

jedis多线程异常

多线程下使用jedis会报一些奇怪的错误

[2013.09.13 11:17:19.280]redis.clients.jedis.exceptions.JedisConnectionException: Unknown reply: 2
[2013.09.13 11:17:19.280]	at redis.clients.jedis.Protocol.process(Protocol.java:71)
[2013.09.13 11:17:19.280]	at redis.clients.jedis.Protocol.read(Protocol.java:122)
[2013.09.13 11:17:19.280]	at redis.clients.jedis.Connection.getBinaryBulkReply(Connection.java:172)
[2013.09.13 11:17:19.280]	at redis.clients.jedis.Connection.getBulkReply(Connection.java:161)
[2013.09.13 11:17:19.280]	at redis.clients.jedis.Jedis.get(Jedis.java:65)
[2013.09.13 11:17:19.280]	at com.youku.index.web.manager.ProManager.getShowSearchCurve(ProManager.java:916)
[2013.09.13 11:17:19.280]	at com.youku.index.web.util.MergeFullkpi.mergeFull(MergeFullkpi.java:59)
[2013.09.13 11:17:19.280]	at com.youku.index.web.manager.ProManager.getAllShowVV(ProManager.java:836)
[2013.09.13 11:17:19.280]	at com.youku.index.web.action.ProAction.vrShow(ProAction.java:422)
[2013.09.13 11:17:19.280]	at sun.reflect.GeneratedMethodAccessor87.invoke(Unknown Source)
[2013.09.13 11:17:19.280]	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[2013.09.13 11:17:19.280]	at java.lang.reflect.Method.invoke(Method.java:597)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:450)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:289)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:252)
[2013.09.13 11:17:19.280]	at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:167)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:265)
[2013.09.13 11:17:19.280]	at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:68)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:239)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:239)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:191)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:73)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:91)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:252)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:100)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:141)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:161)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:193)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:189)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54)
[2013.09.13 11:17:19.280]	at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:563)
[2013.09.13 11:17:19.280]	at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
[2013.09.13 11:17:19.280]	at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99)
[2013.09.13 11:17:19.280]	at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:76)
[2013.09.13 11:17:19.280]	at com.caucho.server.webapp.DispatchFilterChain.doFilter(DispatchFilterChain.java:97)
[2013.09.13 11:17:19.280]	at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:241)
[2013.09.13 11:17:19.280]	at com.caucho.server.webapp.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:280)
[2013.09.13 11:17:19.280]	at com.caucho.server.webapp.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:108)
[2013.09.13 11:17:19.280]	at org.tuckey.web.filters.urlrewrite.NormalRewrittenUrl.doRewrite(NormalRewrittenUrl.java:213)
[2013.09.13 11:17:19.280]	at org.tuckey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:171)
[2013.09.13 11:17:19.280]	at org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:145)
[2013.09.13 11:17:19.280]	at org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:92)
[2013.09.13 11:17:19.280]	at org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:381)
[2013.09.13 11:17:19.280]	at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:76)
[2013.09.13 11:17:19.280]	at com.caucho.server.cache.CacheFilterChain.doFilter(CacheFilterChain.java:158)
[2013.09.13 11:17:19.280]	at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:178)
[2013.09.13 11:17:19.280]	at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:241)
[2013.09.13 11:17:19.280]	at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:268)
[2013.09.13 11:17:19.280]	at com.caucho.server.port.TcpConnection.run(TcpConnection.java:586)
[2013.09.13 11:17:19.280]	at com.caucho.util.ThreadPool$Item.runTasks(ThreadPool.java:690)
[2013.09.13 11:17:19.280]	at com.caucho.util.ThreadPool$Item.run(ThreadPool.java:612)
[2013.09.13 11:17:19.280]	at java.lang.Thread.run(Thread.java:662)

jedis并不是线程安全的,于是在程序中改为每个线程只使用一个jedis实例。
较好的解决办法是使用JedisPool,见官方文档:https://github.com/xetorthio/jedis/wiki/Getting-started
先初始化一个池,可以设置一些参数,如setMaxActive,setMaxIdle等:
查看源代码打印帮助
JedisPool pool = new JedisPool(new JedisPoolConfig(), “localhost”);
然后就可以从池中取出一个实例:

Jedis jedis = pool.getResource();
try {
  /// ... do stuff here ... for example
  jedis.set("foo", "bar");
  String foobar = jedis.get("foo");
  jedis.zadd("sose", 0, "car"); jedis.zadd("sose", 0, "bike");
  Set<String> sose = jedis.zrange("sose", 0, -1);
} finally {
  /// ... it's important to return the Jedis instance to the pool once you've finished using it
  pool.returnResource(jedis);
}
/// ... when closing your application:
pool.destroy();

用完要记得放回池,不用了需要销毁。
转自
http://www.rigongyizu.com/jedis-multithread-exception/
不过还没来得及实现,标记下……

eclipse插件FileSync自动同步文件到tomcat

eclipse插件FileSync自动同步文件到tomcat
tomcat server.xml 配置

<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true" xmlNamespaceAware="false" xmlValidation="false">
        <Context path="" docBase="E:web3.4targetweb-0.0.1-SNAPSHOT" reloadable="true">
<!-- 					<Resource name="jdbc/biee-web" -->
<!-- 						factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory" auth="Container" -->
<!-- 						type="javax.sql.DataSource"  -->
<!-- 						maxActive="20"  -->
<!-- 						maxIdel="10"  -->
<!-- 						maxWait="1000" -->
<!-- 						username="bieeweb"  -->
<!-- 						password="bieeweb001"  -->
<!-- 						driverClassName="oracle.jdbc.driver.OracleDriver" -->
<!-- 						URIEncoding="UTF-8" -->
<!-- 						url="jdbc:oracle:thin:@10.106.23.154:1523:yktdweb"> -->
<!-- 					</Resource> -->
				</Context>
      </Host>

安装FileSync插件:
注意:不同版本的eclipse需要安装不同版本的插件
Eclipse 3.3 – 3.4:
Go to “Help -> Software Updates -> Find and Install… -> Search for new features to install -> Next -> New Remote Site…”
Eclipse 3.5:
Go to “Help -> Install new Software… -> Work with:”
and use the http://andrei.gmxhome.de/eclipse/ as url.
please do not unzip the FileSync jar file – just copy it to the dropins folder for Eclipse 3.4-3.7, or plugins folder for Eclipse 3.3.
下载地址:http://andrei.gmxhome.de/filesync/links.html
FileSync使用:
工程-》右键-》属性 选择工程目录对应的taget目录即可,如下图:

FileSync 插件的使用

FileSync 插件的使用

java竖线分割字符串的问题

例1:
String[] paraStr = “6010;320100;A”.split(“;”);
System.out.println(Arrays.toString(paraStr));
输出:[6010, 320100, A]
Ok
例2:
String[] paraStr = “6010|320100|A”.split(“|”);
System.out.println(Arrays.toString(paraStr));
输出:[, 6, 0, 1, 0, |, 3, 2, 0, 1, 0, 0, |, A]
NO,和期望值相差甚远
例3:
String[] paraStr = “6010+320100+A”.split(“+”);
System.out.println(Arrays.toString(paraStr));
输出:
Exception in thread “main” java.util.regex.PatternSyntaxException: Dangling meta character ‘+’ near index 0
+
异常!
有现象,才能总结出结论:
使用String.split方法时要注意的问题
在使用String.split方法分隔字符串时,分隔符如果用到一些特殊字符,可能会得不到我们预期的结果。
我们看jdk doc中说明
public String[] split(String regex)
Splits this string around matches of the given regular expression.
参数regex是一个 regular-expression的匹配模式而不是一个简单的String,他对一些特殊的字符可能会出现你预想不到的结果:
1.用竖线 | 分隔字符串,你将得不到预期的结果。
2.用 * 分隔字符串运行将抛出java.util.regex.PatternSyntaxException异常,用加号 + 也是如此。
显然,| + * 不是有效的模式匹配规则表达式,用”\*” “\+”转义后即可得到正确的字符串结果。
“|” 分隔串时虽然能够执行,但是却不是预期的目的,得到的是每个字符的分割,而不是字符串,”\|”转义后即可得到正确的字符串结果。
还有如果想在串中使用””字符,则也需要转义.首先要表达”ab”这个串就应该用”a\b”,如果要分隔就应该这样才能得到正确结果:
String[] aa = “aaa\bbb\bccc”.split(“\\“);
注意:除了使用“\|”外,也可以用”[.]” 进行分隔!
如:
String[] paraStr = “6010|320100|A”.split(“[|]”);
String[] paraStr = “6010.320100.A”.split(“[.]”);
http://www.cnblogs.com/haitao-fan/archive/2013/01/27/2878537.html

字符编码-ASCII

计算机中的信息包括数据信息和控制信息,数据信息又可分为数值和非数值信息。非数值信息和控制信息包括了字母、各种控制符号、图形符号等,它们都以二进制编码方式存入计算机并得以处理,这种对字母和符号进行编码的二进制代码称为字符代码(Character Code)。计算机中常用的字符编码有ASCII码(美国标准信息交换码)和EBCDIC码(扩展的BCD交换码)。
编码
在显示器上看见的文字、图片等信息在电脑里面其实并不是我们看见的样子,即使你知道所有信息都存储在硬盘里,把它拆开也看不见里面有任何东西,只有些盘片。假设,你用显微镜把盘片放大,会看见盘片表面凹凸不平,凸起的地方被磁化,凹的地方是没有被磁化;凸起的地方代表数字1,凹的地方代表数字0。硬盘只能用0和1来表示所有文字、图片等信息。那么字母”A”在硬盘上是如何存储的呢?可能小张计算机存储字母”A”是1100001,而小王存储字母”A”是11000010,这样双方交换信息时就会误解。比如小张把1100001发送给小王,小王并不认为1100001是字母”A”,可能认为这是字母”X”,于是小王在用记事本访问存储在硬盘上的1100001时,在屏幕上显示的就是字母”X”。也就是说,小张和小王使用了不同的编码表。小张用的编码表是ASCII,ASCII编码表把26个字母都一一的对应到2进制1和0上;小王用的编码表可能是EBCDIC,只不过EBCDIC编码与ASCII编码中的字母和01的对应关系不同。一般地说,开放的操作系统(LINUX 、WINDOWS等)采用ASCII 编码,而大型主机系统(MVS 、OS/390等)采用EBCDIC 编码。在发送数据给对方前,需要事先告知对方自己所使用的编码,或者通过转码,使不同编码方案的两个系统可沟通自如。
ASCII
美国(国家)信息交换标准(代)码,一种使用7个或8个二进制位进行编码的方案,最多可以给256个字符(包括字母、数字、标点符号、控制字符及其他符号)分配(或指定)数值。
ASCII码于1961年提出,用于在不同计算机硬件和软件系统中实现数据传输标准化,在大多数的小型机和全部的个人计算机都使用此码。ASCII码划分为两个集合:128个字符的标准ASCII码和附加的128个字符的扩充和ASCII码。比较EBCDIC。其中95个字符可以显示。另外33个不可以显示。 标准ASCII码为7位,扩充为8位。
目前使用最广泛的西文字符集及其编码是 ASCII 字符集和 ASCII 码( ASCII 是 American Standard Code for Information Interchange 的缩写),它同时也被国际标准化组织( International Organization for Standardization, ISO )批准为国际标准。
基本的 ASCII 字符集共有 128 个字符,其中有 96 个可打印字符,包括常用的字母、数字、标点符号等,另外还有 32 个控制字符。标准 ASCII 码使用 7 个二进位对字符进行编码,对应的 ISO 标准为 ISO646 标准。
字母和数字的 ASCII 码的记忆是非常简单的。我们只要记住了一个字母或数字的 ASCII 码(例如记住 A 为 65 , 0 的 ASCII 码为 48 ),知道相应的大小写字母之间差 32 ,就可以推算出其余字母、数字的 ASCII 码。
虽然标准 ASCII 码是 7 位编码,但由于计算机基本处理单位为字节( 1byte = 8bit ),所以一般仍以一个字节来存放一个 ASCII 字符。每一个字节中多余出来的一位(最高位)在计算机内部通常保持为 0 (在数据传输时可用作奇偶校验位)。
由于标准 ASCII 字符集字符数目有限,在实际应用中往往无法满足要求。为此,国际标准化组织又制定了 ISO2022 标准,它规定了在保持与 ISO646 兼容的前提下将 ASCII 字符集扩充为 8 位代码的统一方法。 ISO 陆续制定了一批适用于不同地区的扩充 ASCII 字符集,每种扩充 ASCII 字符集分别可以扩充 128 个字符,这些扩充字符的编码均为高位为 1 的 8 位代码(即十进制数 128~255 ),称为扩展 ASCII 码。
通过了解字符的存储编码,可以解决很多由编码不匹配引起的问题,比如网页乱码、邮件乱码,本文简单扼要地阐明了ASCII编码、EBCDIC编码、GB2312编码、Unicode编码、UTF-8编码、以及Base64编码。
MBCS
GB2312
GBK
Big5
Unicode
http://baike.baidu.com/view/1204863.htm

伪造COOKIE

按照浏览器的约定,只有来自同一域名的cookie才可以读写,而cookie只是浏览器的,对通讯协议无影响,所以要进行cookie欺骗可以有多种途径:
1、跳过浏览器,直接对通讯数据改写
2、修改浏览器,让浏览器从本地可以读写任意域名cookie
3、使用签名脚本,让浏览器从本地可以读写任意域名cookie(有安全问题)
4、欺骗浏览器,让浏览器获得假的域名
其中:
方法1、2需要较专业的编程知识,对普通用户不太合适。
方法3的实现有2种方法:
1、直接使用签名脚本,不需要签名验证,但是产生很严重的安全问题,因为大家都要上网的,如果这样做你的硬盘文件就……
2、对脚本进行签名后再使用签名脚本,但是需要专用的数字签名工具,对普通用户也不合适。
方法4看样子应该是最合适的了,域名欺骗很简单,也不需要什么工具(当然如果你的机器装有web服务器那更好了),下面我以the9为例,以这种方法为基础,阐述一下cookie欺骗的过程(下文中提到的任何服务端的bug,the9都已经做了改进,所以本文对the9无安全方面的影响):
注:我们讨论的cookie是那种不会在硬盘的cookie文件里留下踪迹的cookie,就是那种只在浏览器生存周期内(会话)产生的cookie,如果浏览器关闭(会话结束)那么这个cookie就被删了!

Java系统程序员修炼之道

从2002开始接触Java学会HelloWorld这么经典的程序到如今不知不觉已经十年啦,十年中亲耳听到过不少大牛的演讲,见到过项目中的神人在键盘上运指如飞的编程速度,当时就被震撼了。当编程越来越成体力活,我们还能有自己的思想,还能修炼为Java系统级别的程序员嘛?学习与修炼以下知识与技能,帮你早日达成愿望。
一:Java语言学习
线程(thread),串行化,反射,网络编程,JNI技术,容器(Map,List, Iterator), 类加载器(ClassLoader),输入输出流,垃圾回收机制, 有比较深入的了解,最起码做过项目应用。有过Java项目的性能优化经验,最起码掌握一种性能监视工具的使用,熟悉JVM参数,最起码知道可以在JVM启动时指定不同垃圾回收机制,以及不同垃圾回收机制之间的差别,熟悉JVM参数优化。
二:J2EE方面
最好知道JDBC规范是怎么回事情,面对Oracle数据库如果告诉你JDBC驱动不能用了,你还知道有OCI驱动可以。掌握常见的SQL语句,熟悉JMS, JNDI等组件,掌握一套web开发模式,从前台到后台,有能力整合好这样的框架。理解并掌握MVC思想,像SSH已经实现了MVC的分层,几乎不需要你自己再实现,假设你开发一个简单的Swing程序,你能MVC就说明你真的掌握了MVC的精髓。有能力在J2EE前端开发中构建自己的MVC模式,知道什么是WEB2.0,知道什么是SOA, SaaS, SaaP等含义
三:理解并能合理运用设计模式,UML建模
知道并理解设计模式中蕴含的几种基本原则如:里氏替换原则, 开闭原则,合成复用原则,依赖倒置原则有很好的理解,并能举例说明。对常用的设计模式如工厂模式,单例模式,观察者模式,责任链模式,桥接模式等知道灵活运用,明白什么是回调(Callback)。最后用一位高人话来总结设计模式,它是为了让软件更容易被别人读懂,更容易维护而产生,设计模式本质是程序员之间的交流,如果A用工厂模式设计一个模块B来接替,A只要说该模块是工厂模式实现,B维护起来应该容易得多,所以设计模式是关于交流,不关于代码。切忌滥用设计模式。学会使用UML建模工具至少熟悉一种URL建模工具。
四:注重用户体验,掌握KISS原则,知道欧卡姆剃刀原则
顾客就是上帝这个口号我们已经喊了N年了,程序员的劳动成果最终也需要转换为服务提供给客户,用户体验至关重要,常常看到的场景是功能实现了,软件很难使用,程序员有个很充足的理由我不是美工,其实注重用户体验跟美工八杆子也打不到一起,FoxMail的成功在很大程度是用户体验的成功,友好,清晰的用户提示,强的容错与纠错设计是获得好的用户体验的不二法门。傻瓜相机顾名思义傻子都会使用,这个就著名的KISS原则(Keep it simple and stupid)意思是UI设计要简单明了,傻子一看就知道怎么用,想想我们做出来的东西,对照说明书都不知道怎么用。另外一个就是最著名的例子IPhone手机外观设计,是典型的欧卡姆剃刀设计原则来完成人机交互。
五:自动测试与软件配置管理(SCM)实现
知道什么是软件配置管理,知道Hudson – http://java.net/projects/hudson/运用该工具SCM,知道怎么获取测试代码覆盖率, Java有效代码行数(NCSS),完成firebug, JDepend等工具集成ant/maven。熟悉并注重在开发过程中使用JUnit单元测试,理解白盒测试规范。
六:熟悉常见的网络通信协议
HTTP协议,知道POST, GET的区别是什么,阅读过HTTP相关的RFC文档。学会使用sniffer工具查看数据包,帮助查找与调试程序,知道TCP与UDP的区别,知道并理解E-Mail发送与接受的协议如SMTP, POP3,IMAP等协议,了解MIME与Base64编码。知道组播是怎么回事情。
七:面向市场,永远对新技术保持渴望
计算机技术的发展日新月异,做为IT行业的软件开发人员要不断的给自己充电,更新自己的技术与时代保持同步,同时还要面向市场,华为总裁任正非说过-“华为的技术革新必须面向市场”,作为程序员同样要有市场意识,很多人都后悔没有在android刚出来的时候加以关注学习。那些很早关注android开发技术的很多程序员因此获得丰厚回报。如今HTML5得到越来越多的浏览器厂家支持,你是否已经跟上脚步,开始学习。
八:保持谦虚,三人行必有我师
乔帮主说他要保持初心,努力学习,我等更应该保持谦虚,IT技术发展日新月异,在你眼中不可能实现的技术,也许别人早已经有思路。保持谦虚就有机会吸取别人身上的长处,古人有云:满招损,谦受益。一个得道的高人更是说出了”下下人,上上智”的禅语。永远不要拒绝帮助你周围的人解决难题,解决难题是进步最快途径。不要放弃任何一次可以提升自己技术与能力的机会。
九:养成总结的习惯,不断反思
上学的时候老师常让写小结,也没总结出来所以然,以至于工作以后再也不提这档子事情,建议每个项目做完以后对自己都有个小结,总结自己在项目里面学到了什么,反问自己能不能完成在不需要别人帮助的情况下自己完成这样的系统搭建,是否熟悉与掌握项目中所用到的技术,即使有些东西不是你负责完成的但是什么也不能阻挡一颗求知的心,总结要尽量详细记录你遇到那些难题是怎么一个一个的解决的,下次再遇到你是否可以很快解决或者避免这样的问题。有总结才有提高,孔子曰:学而不思则罔,如果我们只是coding到吐血,不思考,不总结提高,永远不可能有能有本质提高,秦相李斯有云:“泰山不让土壤,故能成其大,河海不择细流,故能就其深”,点滴积累不断总结方能量变导致质变。
十:数学功底与算法知识
用任何编程语言开发应用,都离不开核心算法支持,很多国外的软件单单从UI上看,恐怕写几年程序的人都可以模仿,但是UI之下的那些真实深浅不一,相信不是你想模仿就可以模仿的,为什么我们越来越山寨,因为我们没有核心竞争力,对于程序员来说算法与数学显然是他最重要的核心竞争力之一。《算法导论》,《编程珠玑》等书绝对值得读十遍。微软亚洲研究院视觉计算组负责人在一次演讲中说到他们招人的标准是“三好学生– 数学好,编程好,态度好”。可是现实的普遍情况却是 – 微机原理闹危机,汇编语言不会变,实变函数学十遍。计算机基础知识被大家普遍忽视。从今天开始好好学习吧……
十一:Java代码反编译与代码保护
Java编译产生字节码,因而可以被轻松的逆向工程(反编译),微软的C#生产的DLL也一样可以被轻松反编译。正式由于这个原因产生了许多Java开源的代码保护工具,而Proguard是其中佼佼者,已经被google集成在android之中用于Java代码保护,访问这里了解更多:http://proguard.sourceforge.net/
十二:努力成为某个行业或者领域骨干
面对漫长的职业生涯,要想不被淘汰,必须具备一招鲜吃遍天下的能力,选择自己感兴趣的方向,努力而深入的研究,计算机技术发展到今天已经细分很细,努力研究一种Java开源框架或者开源HTTP服务器源码或者研究过网络爬虫源码或者WEBKIT内核,不愁没有人要你。如果你是非常了解金融,企业ERP,证券,保险,移动应用行业的应用开发业务的人,一样不用愁工作。这些知识不随语言而改变,努力做一个有核心竞争力的Java程序员。
十三:提高语言与书面表达能力,掌握基础的项目管理知识
文档与语言表达能力是最好的向外界展现自己能力的方式,很多程序员编程能力很高,表达能力一般,Linux能够成功,除了归功于网络社区的力量之外,也得益于Linux作者本人给各大基金会写信,宣传推广,试想如果没有良好的书面语言表达能力,即使Linux系统再优秀,却无法被准确表达,失去各大基金会的支持,Linux还会像今天这么好的局面嘛。所以重视文档,重视提升沟通与表达能力,才有可能成为Java系统程序员。掌握基本的2/8原则,学会将模块细化分配给不同的人,预见并控制项目风险,把握项目进度,优化流程,合理的时间管理,了解TDD,熟悉敏捷开发模式,常规软件开发模式。
十四:掌握英语,良好的读写能力
英语是计算机的母语,掌握好英语对于阅读英文资料学习新技术大有帮助,我的建议是尽量读英文原版书,如果是算法方面的可能会困难一点,但是其它像设计模式,软件工程,OO编程思想等尽量读原版,提高自己的英文水平,多多访问开发者,code project,程序员天堂,Pc-magazine等英文IT网站。英语绝对是你必须修炼与提高的技能。此外英语好在外资企业尤其重要,只有外语足够好才可能在外资企业中突破职业瓶颈,向上发展。
转自:http://bbs.csdn.net/topics/390103026

线程池与工作队列

为什么要用线程池?
诸如 Web 服务器、数据库服务器、文件服务器或邮件服务器之类的许多服务器应用程序都面向处理来自某些远程来源的大量短小的任务。请求以某种方式到达服务器,这种方式可能是通过网络协议(例如 HTTP、FTP 或 POP)、通过 JMS 队列或者可能通过轮询数据库。不管请求如何到达,服务器应用程序中经常出现的情况是:单个任务处理的时间很短而请求的数目却是巨大的。
构建服务器应用程序的一个过于简单的模型应该是:每当一个请求到达就创建一个新线程,然后在新线程中为请求服务。实际上,对于原型开发这种方法工作得很好,但如果试图部署以这种方式运行的服务器应用程序,那么这种方法的严重不足就很明显。每个请求对应一个线程(thread-per-request)方法的不足之一是:为每个请求创建一个新线程的开销很大;为每个请求创建新线程的服务器在创建和销毁线程上花费的时间和消耗的系统资源要比花在处理实际的用户请求的时间和资源更多。
除了创建和销毁线程的开销之外,活动的线程也消耗系统资源。在一个 JVM 里创建太多的线程可能会导致系统由于过度消耗内存而用完内存或“切换过度”。为了防止资源不足,服务器应用程序需要一些办法来限制任何给定时刻处理的请求数目。
线程池为线程生命周期开销问题和资源不足问题提供了解决方案。通过对多个任务重用线程,线程创建的开销被分摊到了多个任务上。其好处是,因为在请求到达时线程已经存在,所以无意中也消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使应用程序响应更快。而且,通过适当地调整线程池中的线程数目,也就是当请求的数目超过某个阈值时,就强制其它任何新到的请求一直等待,直到获得一个线程来处理为止,从而可以防止资源不足。
线程池的替代方案
线程池远不是服务器应用程序内使用多线程的唯一方法。如同上面所提到的,有时,为每个新任务生成一个新线程是十分明智的。然而,如果任务创建过于频繁而任务的平均处理时间过短,那么为每个任务生成一个新线程将会导致性能问题。
另一个常见的线程模型是为某一类型的任务分配一个后台线程与任务队列。AWT 和 Swing 就使用这个模型,在这个模型中有一个 GUI 事件线程,导致用户界面发生变化的所有工作都必须在该线程中执行。然而,由于只有一个 AWT 线程,因此要在 AWT 线程中执行任务可能要花费相当长时间才能完成,这是不可取的。因此,Swing 应用程序经常需要额外的工作线程,用于运行时间很长的、同 UI 有关的任务。
每个任务对应一个线程方法和单个后台线程(single-background-thread)方法在某些情形下都工作得非常理想。每个任务一个线程方法在只有少量运行时间很长的任务时工作得十分好。而只要调度可预见性不是很重要,则单个后台线程方法就工作得十分好,如低优先级后台任务就是这种情况。然而,大多数服务器应用程序都是面向处理大量的短期任务或子任务,因此往往希望具有一种能够以低开销有效地处理这些任务的机制以及一些资源管理和定时可预见性的措施。线程池提供了这些优点。
工作队列
就线程池的实际实现方式而言,术语“线程池”有些使人误解,因为线程池“明显的”实现在大多数情形下并不一定产生我们希望的结果。术语“线程池”先于 Java 平台出现,因此它可能是较少面向对象方法的产物。然而,该术语仍继续广泛应用着。
虽然我们可以轻易地实现一个线程池类,其中客户机类等待一个可用线程、将任务传递给该线程以便执行、然后在任务完成时将线程归还给池,但这种方法却存在几个潜在的负面影响。例如在池为空时,会发生什么呢?试图向池线程传递任务的调用者都会发现池为空,在调用者等待一个可用的池线程时,它的线程将阻塞。我们之所以要使用后台线程的原因之一常常是为了防止正在提交的线程被阻塞。完全堵住调用者,如在线程池的“明显的”实现的情况,可以杜绝我们试图解决的问题的发生。
我们通常想要的是同一组固定的工作线程相结合的工作队列,它使用 wait() 和 notify() 来通知等待线程新的工作已经到达了。该工作队列通常被实现成具有相关监视器对象的某种链表。清单 1 显示了简单的合用工作队列的示例。尽管 Thread API 没有对使用 Runnable 接口强加特殊要求,但使用 Runnable 对象队列的这种模式是调度程序和工作队列的公共约定。
清单 1. 具有线程池的工作队列

public class WorkQueue
{
    private final int nThreads;
    private final PoolWorker[] threads;
    private final LinkedList queue;
    public WorkQueue(int nThreads)
    {
        this.nThreads = nThreads;
        queue = new LinkedList();
        threads = new PoolWorker[nThreads];
        for (int i=0; i            threads[i] = new PoolWorker();
            threads[i].start();
        }
    }
    public void execute(Runnable r) {
        synchronized(queue) {
            queue.addLast(r);
            queue.notify();
        }
    }
    private class PoolWorker extends Thread {
        public void run() {
            Runnable r;
            while (true) {
                synchronized(queue) {
                    while (queue.isEmpty()) {
                        try
                        {
                            queue.wait();
                        }
                        catch (InterruptedException ignored)
                        {
                        }
                    }
                    r = (Runnable) queue.removeFirst();
                }
                // If we don't catch RuntimeException,
                // the pool could leak threads
                try {
                    r.run();
                }
                catch (RuntimeException e) {
                    // You might want to log something here
                }
            }
        }
    }
}

您可能已经注意到了清单 1 中的实现使用的是 notify() 而不是 notifyAll() 。大多数专家建议使用 notifyAll() 而不是 notify() ,而且理由很充分:使用 notify() 具有难以捉摸的风险,只有在某些特定条件下使用该方法才是合适的。另一方面,如果使用得当, notify() 具有比 notifyAll() 更可取的性能特征;特别是, notify() 引起的环境切换要少得多,这一点在服务器应用程序中是很重要的。
清单 1 中的示例工作队列满足了安全使用 notify() 的需求。因此,请继续,在您的程序中使用它,但在其它情形下使用 notify() 时请格外小心。
使用线程池的风险
虽然线程池是构建多线程应用程序的强大机制,但使用它并不是没有风险的。用线程池构建的应用程序容易遭受任何其它多线程应用程序容易遭受的所有并发风险,诸如同步错误和死锁,它还容易遭受特定于线程池的少数其它风险,诸如与池有关的死锁、资源不足和线程泄漏。
死锁
任何多线程应用程序都有死锁风险。当一组进程或线程中的每一个都在等待一个只有该组中另一个进程才能引起的事件时,我们就说这组进程或线程 死锁了。死锁的最简单情形是:线程 A 持有对象 X 的独占锁,并且在等待对象 Y 的锁,而线程 B 持有对象 Y 的独占锁,却在等待对象 X 的锁。除非有某种方法来打破对锁的等待(Java 锁定不支持这种方法),否则死锁的线程将永远等下去。
虽然任何多线程程序中都有死锁的风险,但线程池却引入了另一种死锁可能,在那种情况下,所有池线程都在执行已阻塞的等待队列中另一任务的执行结果的任务,但这一任务却因为没有未被占用的线程而不能运行。当线程池被用来实现涉及许多交互对象的模拟,被模拟的对象可以相互发送查询,这些查询接下来作为排队的任务执行,查询对象又同步等待着响应时,会发生这种情况。
资源不足
线程池的一个优点在于:相对于其它替代调度机制(有些我们已经讨论过)而言,它们通常执行得很好。但只有恰当地调整了线程池大小时才是这样的。线程消耗包括内存和其它系统资源在内的大量资源。除了 Thread 对象所需的内存之外,每个线程都需要两个可能很大的执行调用堆栈。除此以外,JVM 可能会为每个 Java 线程创建一个本机线程,这些本机线程将消耗额外的系统资源。最后,虽然线程之间切换的调度开销很小,但如果有很多线程,环境切换也可能严重地影响程序的性能。
如果线程池太大,那么被那些线程消耗的资源可能严重地影响系统性能。在线程之间进行切换将会浪费时间,而且使用超出比您实际需要的线程可能会引起资源匮乏问题,因为池线程正在消耗一些资源,而这些资源可能会被其它任务更有效地利用。除了线程自身所使用的资源以外,服务请求时所做的工作可能需要其它资源,例如 JDBC 连接、套接字或文件。这些也都是有限资源,有太多的并发请求也可能引起失效,例如不能分配 JDBC 连接。
并发错误
线程池和其它排队机制依靠使用 wait() 和 notify() 方法,这两个方法都难于使用。如果编码不正确,那么可能丢失通知,导致线程保持空闲状态,尽管队列中有工作要处理。使用这些方法时,必须格外小心;即便是专家也可能在它们上面出错。而最好使用现有的、已经知道能工作的实现,例如在下面的 无须编写您自己的池中讨论的 util.concurrent 包。
线程泄漏
各种类型的线程池中一个严重的风险是线程泄漏,当从池中除去一个线程以执行一项任务,而在任务完成后该线程却没有返回池时,会发生这种情况。发生线程泄漏的一种情形出现在任务抛出一个 RuntimeException 或一个 Error 时。如果池类没有捕捉到它们,那么线程只会退出而线程池的大小将会永久减少一个。当这种情况发生的次数足够多时,线程池最终就为空,而且系统将停止,因为没有可用的线程来处理任务。
有些任务可能会永远等待某些资源或来自用户的输入,而这些资源又不能保证变得可用,用户可能也已经回家了,诸如此类的任务会永久停止,而这些停止的任务也会引起和线程泄漏同样的问题。如果某个线程被这样一个任务永久地消耗着,那么它实际上就被从池除去了。对于这样的任务,应该要么只给予它们自己的线程,要么只让它们等待有限的时间。
请求过载
仅仅是请求就压垮了服务器,这种情况是可能的。在这种情形下,我们可能不想将每个到来的请求都排队到我们的工作队列,因为排在队列中等待执行的任务可能会消耗太多的系统资源并引起资源缺乏。在这种情形下决定如何做取决于您自己;在某些情况下,您可以简单地抛弃请求,依靠更高级别的协议稍后重试请求,您也可以用一个指出服务器暂时很忙的响应来拒绝请求。
有效使用线程池的准则
只要您遵循几条简单的准则,线程池可以成为构建服务器应用程序的极其有效的方法:
不要对那些同步等待其它任务结果的任务排队。这可能会导致上面所描述的那种形式的死锁,在那种死锁中,所有线程都被一些任务所占用,这些任务依次等待排队任务的结果,而这些任务又无法执行,因为所有的线程都很忙。
在为时间可能很长的操作使用合用的线程时要小心。如果程序必须等待诸如 I/O 完成这样的某个资源,那么请指定最长的等待时间,以及随后是失效还是将任务重新排队以便稍后执行。这样做保证了:通过将某个线程释放给某个可能成功完成的任务,从而将最终取得 某些进展。
理解任务。要有效地调整线程池大小,您需要理解正在排队的任务以及它们正在做什么。它们是 CPU 限制的(CPU-bound)吗?它们是 I/O 限制的(I/O-bound)吗?您的答案将影响您如何调整应用程序。如果您有不同的任务类,这些类有着截然不同的特征,那么为不同任务类设置多个工作队列可能会有意义,这样可以相应地调整每个池。
调整池的大小
调整线程池的大小基本上就是避免两类错误:线程太少或线程太多。幸运的是,对于大多数应用程序来说,太多和太少之间的余地相当宽。
请回忆:在应用程序中使用线程有两个主要优点,尽管在等待诸如 I/O 的慢操作,但允许继续进行处理,并且可以利用多处理器。在运行于具有 N 个处理器机器上的计算限制的应用程序中,在线程数目接近 N 时添加额外的线程可能会改善总处理能力,而在线程数目超过 N 时添加额外的线程将不起作用。事实上,太多的线程甚至会降低性能,因为它会导致额外的环境切换开销。
线程池的最佳大小取决于可用处理器的数目以及工作队列中的任务的性质。若在一个具有 N 个处理器的系统上只有一个工作队列,其中全部是计算性质的任务,在线程池具有 N 或 N+1 个线程时一般会获得最大的 CPU 利用率。
对于那些可能需要等待 I/O 完成的任务(例如,从套接字读取 HTTP 请求的任务),需要让池的大小超过可用处理器的数目,因为并不是所有线程都一直在工作。通过使用概要分析,您可以估计某个典型请求的等待时间(WT)与服务时间(ST)之间的比例。如果我们将这一比例称之为 WT/ST,那么对于一个具有 N 个处理器的系统,需要设置大约 N*(1+WT/ST) 个线程来保持处理器得到充分利用。
处理器利用率不是调整线程池大小过程中的唯一考虑事项。随着线程池的增长,您可能会碰到调度程序、可用内存方面的限制,或者其它系统资源方面的限制,例如套接字、打开的文件句柄或数据库连接等的数目。
无须编写您自己的池
Doug Lea 编写了一个优秀的并发实用程序开放源码库 util.concurrent ,它包括互斥、信号量、诸如在并发访问下执行得很好的队列和散列表之类集合类以及几个工作队列实现。该包中的 PooledExecutor 类是一种有效的、广泛使用的以工作队列为基础的线程池的正确实现。您无须尝试编写您自己的线程池,这样做容易出错,相反您可以考虑使用 util.concurrent 中的一些实用程序。参阅 参考资料以获取链接和更多信息。
util.concurrent 库也激发了 JSR 166,JSR 166 是一个 Java 社区过程(Java Community Process (JCP))工作组,他们正在打算开发一组包含在 java.util.concurrent 包下的 Java 类库中的并发实用程序,这个包应该用于 Java 开发工具箱 1.5 发行版。
结束语
线程池是组织服务器应用程序的有用工具。它在概念上十分简单,但在实现和使用一个池时,却需要注意几个问题,例如死锁、资源不足和 wait() 及 notify() 的复杂性。如果您发现您的应用程序需要线程池,那么请考虑使用 util.concurrent 中的某个 Executor 类,例如 PooledExecutor ,而不用从头开始编写。如果您要自己创建线程来处理生存期很短的任务,那么您绝对应该考虑使用线程池来替代。

memcache在linux下的安装

大前提:安装gcc 

输出表明缺少gcc

输出表明缺少gcc


最简单的是yum安装:
yum -y install gcc
1、libevent是安装 memcached 的唯一前提条件。它是 memcached 所依赖的异步事件通知库。

tar -zxvf  libevent-1.4.11-stable.tar.gz
./configure
make
make install

configure

configure


make

make


make install

make install


2、memcache安装

./configure
make
make install

mem configure

mem configure


mem make

mem make


mem make install

mem make install


3、memcache启动

./memcached -d -m 1024 -u root -p 11211 -c 1024 -P /root/memcache_api_1.pid -t 24

memcached启动参数描述:
-d :启动一个守护进程
-m :分配给Memcache使用的内存数量,单位是MB,默认是64MB,
-u :运行Memcache的用户
-l :监听的服务器IP地址
-p :设置Memcache监听的端口,默认是11211 注:-p(p为小写)
-c :设置最大并发连接数,默认是1024
-P :设置保存Memcache的pid文件 注:-P(P为大写)
4、验证启动
ps -ef | grep memcached | grep 11211

查看是否存在进程

查看是否存在进程


验证memcache安装是否成功

验证memcache安装是否成功


5、命令说明
command

key key 用于查找缓存值
flags 可以包括键值对的整型参数,客户机使用它存储关于键值对的额外信息
expiration time 在缓存中保存键值对的时间长度(以秒为单位,0 表示永远)
bytes 在缓存中存储的字节点
value 存储的值(始终位于第二行)
6、通过进程号kill掉memcache进程
kill -9 3146

xss攻击

恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意用户的特殊目的。
XSS的种类:
XSS攻击分成两类,一类是来自内部的攻击,主要指的是利用程序自身的漏洞,构造跨站语句,如:dvbbs的showerror.asp存在的跨站漏洞。
另一类则是来自外部的攻击,主要指的自己构造XSS跨站漏洞网页或者寻找非目标机以外的有跨站漏洞的网页。如当我们要渗透一个站点,我们自己构造一个有跨站漏洞的网页,然后构造跨站语句,通过结合其它技术,如社会工程学等,欺骗目标服务器的管理员打开。
XSS漏洞是Web应用程序中最常见的漏洞之一。如果您的站点没有预防XSS漏洞的固定方法,那么就存在XSS漏洞。这个利用XSS漏洞的病毒之所以具有重要意义是因为,通常难以看到XSS漏洞的威胁,而该病毒则将其发挥得淋漓尽致。
XSS工作流程:
1)恶意用户,在一些公共区域(例如,建议提交表单或消息公共板的输入表单)输入一些文本,这些文本被其它用户看到,但这些文本不仅仅是他们要输入的文本,同时还包括一些可以在客户端执行的脚本。如:

2)恶意提交这个表单
3)其他用户看到这个包括恶意脚本的页面并执行,获取用户的cookie等敏感信息。
例子:
site:suning.com inurl:callback