﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-在路上-随笔分类-Java</title><link>http://www.blogjava.net/gumingcn/category/44166.html</link><description>路上有惊慌，路上有理想</description><language>zh-cn</language><lastBuildDate>Wed, 18 Apr 2012 04:35:36 GMT</lastBuildDate><pubDate>Wed, 18 Apr 2012 04:35:36 GMT</pubDate><ttl>60</ttl><item><title>记录：java批量生成图片的问题</title><link>http://www.blogjava.net/gumingcn/archive/2012/04/18/375080.html</link><dc:creator>阮步兵</dc:creator><author>阮步兵</author><pubDate>Wed, 18 Apr 2012 03:35:00 GMT</pubDate><guid>http://www.blogjava.net/gumingcn/archive/2012/04/18/375080.html</guid><wfw:comment>http://www.blogjava.net/gumingcn/comments/375080.html</wfw:comment><comments>http://www.blogjava.net/gumingcn/archive/2012/04/18/375080.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gumingcn/comments/commentRss/375080.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gumingcn/services/trackbacks/375080.html</trackback:ping><description><![CDATA[1.linux安装字体<br />&nbsp;&nbsp; 以微软雅黑为例，找到msyh.ttf ,copy至下面的文件夹<br /><div>&nbsp;&nbsp; usr/share/fonts/msyh</div> <div>&nbsp; 执行命令：fc-cache -fv</div>&nbsp; 重启jvm即可<br />2.drawString 部分代码<br /><div>private static BufferedImage drawString(int type, boolean isWhite,<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;int width, int height, String price, Font font_money, Font font,<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Graphics2D g2d, Rectangle2D bounds, Rectangle2D bounds_money) {<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; BufferedImage image;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; //透明背景<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; image = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT); &nbsp;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; g2d.dispose(); &nbsp;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; g2d = image.createGraphics(); &nbsp;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; //反锯齿字体<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; if(!isWhite){<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; //非白字<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; g2d.setColor(new Color(236,0,137)); &nbsp;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; }else{<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //白字<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g2d.setColor(new Color(255,255,255)); &nbsp;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; }<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; //字体居中<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; double y = (height - bounds.getHeight()) / 2;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; double ascent = -bounds.getY();&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; double baseY = y + ascent;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br /><br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; g2d.setStroke(new BasicStroke(1)); &nbsp;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; g2d.setFont(font_money);<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; g2d.drawString(FONT_RMB_CHAR, -2, (int)baseY); &nbsp;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; g2d.setFont(font);<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; g2d.drawString(price, (int)bounds_money.getWidth()-4, (int)baseY);<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; g2d.dispose();<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; return image;<br />&nbsp;&nbsp; &nbsp;}</div><div>3.如果需要根据字符串的长度生成图片的宽度，可以使用如下方法</div><div>&nbsp;Rectangle2D bounds = font.getStringBounds(price, context);<br />&nbsp;width = (int)(bounds.getWidth();<br /><br />4.批量生成,使用java自带的线程池，并使用CompletionService，目的是在线程处理结束后得到生成成功的ProductId<br /><div>&nbsp;&nbsp; &nbsp;&nbsp; public boolean generateImagesBatch(){<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; boolean flag=true;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; ExecutorService exec = Executors.newFixedThreadPool(8);<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; CompletionService&lt;CallBack&gt; completionService=<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new ExecutorCompletionService&lt;CallBack&gt;(exec);<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; long startTime=System.currentTimeMillis();<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp;String sql="select productId,price from prod";<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;List&lt;Map&gt; skuList = this.cmsJdbcTemplate.queryForList(sql);<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;for(Map map:skuList){<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;String prodId=((BigDecimal)map.get("productId")).toString();<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;double price=((BigDecimal)map.get("price")).doubleValue();<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;completionService.submit(new CreateImageConcurrent(prodId,price,FontEnum.ONE,false));&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; completionService.submit(new CreateImageConcurrent(prodId,price,FontEnum.TWO,false));&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;long endTime=System.currentTimeMillis()-startTime;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;log.info("query db time&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;"+endTime/1000);<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Future&lt;CallBack&gt; future;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;int count=skuList.size()*6;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;log.info("generateImagesBatch count:"+count);<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;try {<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;while(count&gt;0){<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; future = completionService.take();<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;CallBack callBack = future.get();<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if(null!=callBack){<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;count--; log.info("generateImagesBatch prod id:"+callBack.getSuccesMessage());&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;endTime=System.currentTimeMillis()-startTime;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;log.info("create images time&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;"+endTime/1000);<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;log.info("generateImagesBatch success!");<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;flag=true;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;} catch (ExecutionException e) {<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;flag=false;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;log.error("generateImagesBatch fail::ExecutionException::"+e.getMessage());<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;} catch (InterruptedException e) {<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;flag=false;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;log.error("generateImagesBatch fail::InterruptedException::"+e.getMessage());<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}finally{<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;exec.shutdown();<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return flag;<br />&nbsp;&nbsp; &nbsp;&nbsp; }</div></div><img src ="http://www.blogjava.net/gumingcn/aggbug/375080.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gumingcn/" target="_blank">阮步兵</a> 2012-04-18 11:35 <a href="http://www.blogjava.net/gumingcn/archive/2012/04/18/375080.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java多线程笔记(4)</title><link>http://www.blogjava.net/gumingcn/archive/2010/12/15/340691.html</link><dc:creator>阮步兵</dc:creator><author>阮步兵</author><pubDate>Wed, 15 Dec 2010 10:18:00 GMT</pubDate><guid>http://www.blogjava.net/gumingcn/archive/2010/12/15/340691.html</guid><wfw:comment>http://www.blogjava.net/gumingcn/comments/340691.html</wfw:comment><comments>http://www.blogjava.net/gumingcn/archive/2010/12/15/340691.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gumingcn/comments/commentRss/340691.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gumingcn/services/trackbacks/340691.html</trackback:ping><description><![CDATA[以下只是一些概念<br />
<br />
<br />
1.<a name="N1008F"><span class="atitle">Semaphore</span></a>与<a name="N100B4"><span class="atitle">CountDownLatch<br />
&nbsp; </span></a><a name="N1008F"><span class="atitle">Semaphore 可用于控制</span>特定资源请求（线程/操作）数量<br />
&nbsp; </a><a name="N100B4"><span class="atitle">CountDownLatch 在功能上类似于</span></a><a name="N1008F"><span class="atitle">Semaphore。区别是，</span></a><a name="N1008F"><span class="atitle">Semaphore允许一次一个线程的话，</span></a><a name="N100B4"><span class="atitle">CountDownLatch可以允许多个线程在特定的时间一起执行。<br />
<br />
2.CAS操作<br />
&nbsp; 根据英文直译其实可以理解其含义，compare and set.</span><br />
</a>
<p>&nbsp;
CAS 操作包含三个操作数 ——
内存位置（V）、预期原值（A）和新值(B)。如果内存位置的值与预期原值相匹配，那么处理器会自动将该位置值更新为新值。否则，处理器不做任何操作。CAS 认为位置 V 应该包含值 A；如果包含该值，则将 B 放到这个位置；否则，不要更改该位置，只告诉我这个位置现在的值即可通常将 CAS 用于同步的方式是从地址 V 读取值 A，执行多步计算来获得新值 B，然后使用 CAS 将 V 的值从 A 改为 B。如果 V 处的值尚未同时更改，则 CAS 操作成功。 <br />
</p>
<p>3.ABA问题</p>
<p>&nbsp; 因为在更改 V 之前，CAS 主要询问&#8220;V 的值是否仍为 A&#8221;，所以在第一次读取 V 以及对 V 执行 CAS 操作之前，如果将值从 A 改为
B，然后再改回 A，会使基于 CAS 的算法混乱。在这种情况下，CAS 操作会成功，但是在一些情况下，结果可能不是您所预期的。这类问题称为
<em>ABA 问题</em>。<code></code></p>
<p>4.原子操作</p>
<p>&nbsp;&nbsp; A与B两个操作。从执行A的线程看，当其他线程执行B时，要么B全部执行完成，要么一点都不执行。这样A与B互为原子操作。要保证数据状态的一致性，要在单一的原子操作中更新所有相关联的状态。</p>
5.可见性<br />
&nbsp; <br />
&nbsp;&nbsp; 在单线程环境下，读写操作都在一个线程内完成，不存在可见性问题。但是，当读与写操作不在同一个线程内时，就需要有可见性的要求——即可变的共享变量对所有线程都是可见的。<br />
<p>6.重排序</p>
<p>&nbsp;&nbsp;&nbsp; JVM实现中，线程内部维持顺序化语义。如果程序的最终结果等同于它在严格的顺序化环境下的结果，那么指令的执行顺序就可能与代码的顺序不一致。这个过程通过叫做指令的重排序。比如Java存储模型允许编译器重排序操作指令，在寄存器中缓存数值，还允许CPU重排序，并在处理器的缓存中缓存数值。<br />
</p>
<p>&nbsp;&nbsp; 当然，在没有同步的多线程情况下，编译器，处理器，运行时安排操作的执行顺序可能完全出人意料。</p>
<p>7.内部锁</p>
<p>&nbsp;
每个Java对象都可以隐士的扮演一个用于同步的锁的角色。比如synchronized(object){},执行线程进入synchronized块
之前自动获得锁。无论是正确执行或是抛出异常，最终都会释放该锁。内部锁是一种互斥锁(mutex)——至多只有一个线程可以拥有锁。JDK中有该锁的实
现。</p>
<p>8.锁与内存</p>
<p>&nbsp;&nbsp; 锁不仅仅是关于同步与互斥，也是关于内存可见性的。为了保证所有线程都能访问共享变量的最新值，读和写的线程必须使用公用的锁进行同步。</p>
<p>9.锁与volatile</p>
<p>&nbsp;&nbsp; 加锁可以保证可见性与原子性，volatile只能保证可见性。</p>
<p>10.happen-before法则</p>
<p>&nbsp; Java存储模型有一个happens-before原则，就是如果动作B要看到动作A的执行结果（无论A/B是否在同一个线程里面执行），那么A/B就需要满足happens-before关系。比如一个对象构造函数的结束happens-before与该对象的finalizer的开始</p>
<p><br />
</p>
<p>参考:https://www.ibm.com/developerworks/cn/java/j-jtp11234/</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; http://www.ibm.com/developerworks/cn/java/j-5things5.html</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; http://www.blogjava.net/xylz/archive/2010/07/03/325168.html</p>
<p>&nbsp;&nbsp;&nbsp; 《Java 并发编程实践》<br />
<strong></strong><font size="4"><strong></strong></font>
</p>
<img src ="http://www.blogjava.net/gumingcn/aggbug/340691.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gumingcn/" target="_blank">阮步兵</a> 2010-12-15 18:18 <a href="http://www.blogjava.net/gumingcn/archive/2010/12/15/340691.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>BTrace 工具使用(1)</title><link>http://www.blogjava.net/gumingcn/archive/2010/12/10/340291.html</link><dc:creator>阮步兵</dc:creator><author>阮步兵</author><pubDate>Fri, 10 Dec 2010 10:30:00 GMT</pubDate><guid>http://www.blogjava.net/gumingcn/archive/2010/12/10/340291.html</guid><wfw:comment>http://www.blogjava.net/gumingcn/comments/340291.html</wfw:comment><comments>http://www.blogjava.net/gumingcn/archive/2010/12/10/340291.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/gumingcn/comments/commentRss/340291.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gumingcn/services/trackbacks/340291.html</trackback:ping><description><![CDATA[<span style="font-size: small;"><span lang="EN-US"><span style="font-family: calibri;">BTrace</span></span></span><span style="font-size: small;"><span>是一个实时监控工具，使用了</span><span lang="EN-US"><span style="font-family: calibri;">java agent </span></span><span>和</span><span lang="EN-US"><span style="font-family: calibri;">jvm attach</span></span><span>技术，可以在product的情况下实时监控线上程序的运行情况</span></span>。另，有插件可与visualVM一起使用。<br />
不多说了，具体的可见:<span lang="EN-US"><a href="http://kenai.com/projects/btrace"><span style="font-family: calibri; font-size: small;">http://kenai.com/projects/btrace</span></a></span><br />
<br />
下面介绍几个Helloworld示例:<br />
主要使用了btrace命令:btrace [pid] class<br />
<br />
pid可由jps命令快速查询<br />
<br />
1.监控方法输入参数:<br />
&nbsp;@OnMethod(<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clazz="com.btrace.Person",<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; method="/set.*/"<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; )<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, AnyType[] args) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; println(pcn);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; println(pmn);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printArray(args);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
<br />
执行btract命令<br />
后台输出:<br />
com.btrace.Person<br />
setId<br />
[1, ]&#8230;&#8230;<br />
<br />
2.监控方法返回值<br />
&nbsp; @OnMethod(<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; clazz="com.btrace.Person", <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; method="/get.*/",<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; location=@Location(Kind.RETURN)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; )&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; &nbsp;public static void defineclass(@Return String cl) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; println(Strings.strcat("getValue ", cl));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Threads.jstack();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }<br />
执行btract命令<br />
后台输出:<br />
getValue gum<br />
com.btrace.TestThread.main(TestThread.java:23)<br />
<br />
3.监控jvm内存使用情况<br />
&nbsp; @OnTimer(4000)<br />
&nbsp;&nbsp;&nbsp; public static void printMem() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; println("Heap:");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; println(heapUsage());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; println("Non-Heap:");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; println(nonHeapUsage());<br />
&nbsp;&nbsp;&nbsp; }<br />
执行btract命令<br />
后台输出:<br />
Heap:<br />
init = 268435456(262144K) used = 26175176(25561K) committed = 251658240(245760K)<br />
&nbsp;max = 492175360(480640K)<br />
Non-Heap:<br />
init = 12746752(12448K) used = 5892104(5754K) committed = 13598720(13280K) max =<br />
&nbsp;100663296(98304K)<br />
4.监控方法执行时间<br />
&nbsp;&nbsp; @TLS private static long startTime;<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; @OnMethod(clazz="com.btrace.Person",method="setId")<br />
&nbsp;&nbsp;&nbsp; public static void onCall(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; println("enter this method");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; startTime=timeMillis();<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; @OnMethod(clazz="com.btrace.Person",method="setId",location=@Location(Kind.RETURN))<br />
&nbsp;&nbsp;&nbsp; public static void onReturn(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; println("method end!");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; println(strcat("Time taken ms",str(timeMillis()-startTime)));<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; 后台输出:<br />
&nbsp;&nbsp; enter this method<br />
&nbsp;&nbsp; method end!<br />
&nbsp;&nbsp; Time taken ms0<br />
5.监控Thread start<br />
&nbsp;@OnMethod(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clazz="java.lang.Thread",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; method="start"<br />
&nbsp;&nbsp;&nbsp; )<br />
&nbsp;&nbsp;&nbsp; public static void func() {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; println("about to start a thread!");<br />
&nbsp;&nbsp;&nbsp; }<br />
后台输出：about to start a thread!<br />
<img src ="http://www.blogjava.net/gumingcn/aggbug/340291.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gumingcn/" target="_blank">阮步兵</a> 2010-12-10 18:30 <a href="http://www.blogjava.net/gumingcn/archive/2010/12/10/340291.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java多线程笔记(3)</title><link>http://www.blogjava.net/gumingcn/archive/2010/11/11/337836.html</link><dc:creator>阮步兵</dc:creator><author>阮步兵</author><pubDate>Thu, 11 Nov 2010 09:47:00 GMT</pubDate><guid>http://www.blogjava.net/gumingcn/archive/2010/11/11/337836.html</guid><wfw:comment>http://www.blogjava.net/gumingcn/comments/337836.html</wfw:comment><comments>http://www.blogjava.net/gumingcn/archive/2010/11/11/337836.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gumingcn/comments/commentRss/337836.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gumingcn/services/trackbacks/337836.html</trackback:ping><description><![CDATA[<p><strong>一.限制设计</strong>——从结构上说，是利用封装技术，保证某一时刻只有一个活动访问某个对象。</p>
<p>方式主要三类，方法限制、线程限制和对象内限制</p>
<p><strong>方法限制:</strong></p>
<p>&nbsp;&nbsp; 1.方法内部限制:采用局部变量方式</p>
<p>&nbsp;&nbsp; 2.方法间传递限制：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.调用者copy：比如print(p) 可以改为print(new Point(p));</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b.接收者copy：Point p=new Point(p.x,p.y);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.标量参数：print(int x,int y);d.print(p.x,p.y);</p>
<p><strong>线程限制：</strong></p>
<p>&nbsp; &nbsp;&nbsp; 1.最简单的方法是将所有可变对象都放在一个线程内执行</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public display(){</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new Thread(){</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run(){//do something here}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }.start()</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.线程私有成员变量</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最直接的办法是利用现有类:ThreadLocal.</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当然你可以利用Thread.currentThread()自己实现一个类似功能的类,但Thread.currentThread有限制，就是对特定线程的一类。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 而ThreadLocal则摆脱了这样的限制。而且在线程内对ThreadLocal私有变量的读写不需要同步。</p>
<p><strong>对象限制</strong>：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在前面两种方法都不能做到对对象的限制访问时，你就不得不使用锁。但同时，也可以对对象内部及不同部分的访问进行结构上的限制。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong> </strong>1.适配器模式</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 比如 class Point{</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public double x;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public double y;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public synchronized double getX(){};</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&#8230;&#8230;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; 采用对象限制的设计方式，会将synchronized 锁移除到一个其他对象里，这样就解脱了Point.</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; like this</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class SychPoint {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private final Point point=new Point();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public synchronized double getX(){point.x}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; class Point{</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public double x;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public double y;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public double getX(){};</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; 说白了就是采用适配器模式，改变了一下原来类的结构。java.util.Collection framework 里面就是使用这种策略组织起集合类的同步。</p>
<p>&nbsp;&nbsp; 2.子类化</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将锁延迟到子类实现，这里将不再罗嗦。</p>
<p><strong>二.同步设计</strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 使用锁的注意事项</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.有些入口锁在只有少数线程访问的情况下，可以很好的工作，开销并不大。但是当并发量变大，竞争加剧，开销也变大，系统的性能会随之下降。大多数线程会把大部分时间浪费在等待上。系统出现了延迟，限制了并发系统的优越性。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.使用太多的锁，会增加系统负担，以及不可料的情况发生，比如死锁。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.只用一把锁来保护一个功能的多个方面会导致资源竞争。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.长时间持有锁，会带来性能问题和异常处理的复杂。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5.有时候加锁并不一定能保证得到我们想要的结果。</p>
<p>&nbsp;&nbsp;&nbsp; 对付以上这些问题，没有什么最佳策略，大都需要去权衡各个方面的利弊来进行设计。写多线程的程序，前期的设计比后期维护更为重要。</p>
<p>&nbsp;&nbsp;&nbsp; 初期的设计原则，</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.减少同步</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.用户可以接受陈旧数据，可以拿掉同步，使用volatile</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b.用户在得到非法数据时，只要能得到提示就够了，可以使用double-check方法。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在不同步时check一次，再在同步状态在check一次。这么做的意义在于缩小锁使用范围，在第一次check不满足的情况，跳出方法，那么锁也就用不到了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.只对维护状态部分加锁：当对象的某个同步方法是比较耗时的操作，那么锁持有的时间就越长，而仅仅是为了保持一个状态是，可以采用openCall的方式，减少持有锁时间。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public sychronized void updateState(){}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void readFile(){</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; updateState();//持有锁</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; file.read();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如上，这种方式的前提是程序不需要同步一个方法中无状态的部分。如果整个方法都需要锁，那这种方式就不适用了.</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D.能使用同步块，就不需同步整个方法。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 2.分解同步：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 分解类</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将锁拆分到辅助类中</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 分解锁</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果不愿分解类，可以设计分解锁</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private static Object lock1 = new Object();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private static Object&nbsp; lock2 = new Object();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronize(lock1){}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronized(lock2){}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在jdk 5.0之后的并发包里，已有可重入锁供使用。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 隔离成员变量</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Person的age,income等属性都需要同步处理，以保证并发修改时，可以设计一些同步的int,Double等类型（util.concurrent已提供类似的类），将锁交给辅助类去处理。起到隔离作用.</p>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/gumingcn/aggbug/337836.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gumingcn/" target="_blank">阮步兵</a> 2010-11-11 17:47 <a href="http://www.blogjava.net/gumingcn/archive/2010/11/11/337836.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java多线程笔记(2)</title><link>http://www.blogjava.net/gumingcn/archive/2010/11/03/337163.html</link><dc:creator>阮步兵</dc:creator><author>阮步兵</author><pubDate>Wed, 03 Nov 2010 09:56:00 GMT</pubDate><guid>http://www.blogjava.net/gumingcn/archive/2010/11/03/337163.html</guid><wfw:comment>http://www.blogjava.net/gumingcn/comments/337163.html</wfw:comment><comments>http://www.blogjava.net/gumingcn/archive/2010/11/03/337163.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gumingcn/comments/commentRss/337163.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gumingcn/services/trackbacks/337163.html</trackback:ping><description><![CDATA[<p><span><span><span style="font-size: small;"><strong><span>Java 内存模型</span></strong></span></span></span></p>
<p><span style="font-size: small;">JVM系统中存在一个主内存(Main Memory)，Java中所有变量都储存在主存中，对于所有线程都是共享的。</span><span style="font-size: small;">每条线程都有自己的工作内存(Working Memory)，工作内存中保存的是主存中某些变量的拷贝，线程对所有变量的操作都是在工作内存中进行，线程之间无法相互直接访问，变量传递均需要通过主存完成。</span></p>
<p><span style="font-size: small;">模型的规则：<br />
</span></p>
<p>1.原子性：保证程序得到成员变量（非局部变量）的值或者是初始值，又或者是某线程修改后的，绝对不是多个线程混乱修改后的。</p>
<p>2.可见性(共享内存的数据)：什么情况下，写入成员变量的值对读取该变量的值是可见的？</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; A.写操作释放了同步锁，读操作获得了同步锁</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 原理：释放锁的时候强制线程把所使用的工作内存中的值刷新到主存，获得锁的时候从主存重新装载值。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p.s.锁只被同步块和方法中的操作占有，但却控制了执行该操作的线程的所有成员变量。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; B.如果一个成员变量为volatile,那么在写线程做存储操作前，写入这个成员变量的数据会在主存中刷新，并对其他线程可见。读线程每次使用这个成员变量前都要重新从主存读数据。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; C.如果一个线程访问一个对象的成员变量，读到的值为初始值或者另一个线程修改后的值。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p.s. 不要对引用未完全创建好的对象。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如果一个类可以被子类化，那么在构造函数里启动一个线程是非常危险的</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; D.当一个线程结束后，所有的写入数据都会被刷新到主存。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p.s.同一个线程的不同方法之间传递对象的引用，永远不会有可见性问题</p>
<p>&nbsp;&nbsp; 存储模型保证：如果上面的操作都会发生，那么一个线程对一个成员变量的更新最终对另一个线程是可见的。</p>
<p>3.顺序化(内存操作的顺序)：什么情况下，一个线程的操作可以是无序的？顺序化的问题主要围绕和读写有关的赋值语句的执行顺序。</p>
<p>&nbsp;&nbsp; 如果采用同步机制，那不用多说，顺序化可以保证。</p>
<p>&nbsp;&nbsp; 当没有同步机制时，存储模型所做的保证是难以相信的。在多线程环境下，存储模型是难以保证一定正确的。</p>
<p>&nbsp; 只有当满足下面的三个原则，顺序化才得以保证。</p>
<p>&nbsp;&nbsp; A.从线程执行方法的角度看，如果指令都是串行执行的，那么顺序可以保证</p>
<p>&nbsp;&nbsp; B.保证同步方法或块的顺序执行</p>
<p>&nbsp;&nbsp; C.使用volatile定义成员变量</p>
<p><strong>线程执行过程中，存储模型与锁的关系:</strong></p>
<p style="margin: 0px 0px 10px; padding: 0px;"><span style="font-weight: normal;">(1) 获取对象的锁</span></p>
<p style="margin: 0px 0px 10px; padding: 0px;"><span style="font-weight: normal;">(2) 清空工作内存数据, 从主存复制变量到当前工作内存, 即同步数据 <br />
</span></p>
<p style="margin: 0px 0px 10px; padding: 0px;"><span style="font-weight: normal;">(3) 执行代码，改变共享变量值</span></p>
<p style="margin: 0px 0px 10px; padding: 0px;"><span style="font-weight: normal;">(4) 将工作内存数据刷回主存</span></p>
<p style="margin: 0px 0px 10px; padding: 0px;"><span style="font-weight: normal;">(5) 释放对象的锁 <br />
</span></p>
<p>最后介绍一下volatile关键字</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; volatile定义的成员变量可以保证可见性和顺序化，但不保证原子性。比如count++。<br />
&nbsp;&nbsp;&nbsp;&nbsp; *比如把一个变量声明为volatile，并不能保证这个变量引用的非volatile数据的可见性。比如volatile string[10]（数组）</p>
<p>&nbsp; &nbsp;&nbsp; 正确使用volatile的前提条件</p>
<p>&nbsp; &nbsp;&nbsp; a.对变量的写操作不依赖于当前值</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; b.不要和其他成员变量遵守不变约束。见*处的解释</p>
<p>&nbsp;&nbsp;&nbsp; volatile的应用</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; a.状态标志</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; volatile boolean shutdownFlag;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void shutdown() { shutdownFlag= true; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void doWork() { <br />
&nbsp; &nbsp; &nbsp;&nbsp; while (!shutdownFlag) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // do something<br />
&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; b.假设一个后台线程可能会每隔几秒读取一次数据库里的合同金额，并更新至 volatile 变量。然后，其他线程可以读取这个变量，从而随时能够看到最新的金额。 比较广泛应用在统计类的系统中。</p>
<p>参考文档:</p>
<p>http://www.cs.umd.edu/~pugh/java/memoryModel/</p>
<p>http://www.ibm.com/developerworks/cn/java/j-jtp06197.html</p>
<p>《Java并发编程：设计原则与模式》</p>
<img src ="http://www.blogjava.net/gumingcn/aggbug/337163.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gumingcn/" target="_blank">阮步兵</a> 2010-11-03 17:56 <a href="http://www.blogjava.net/gumingcn/archive/2010/11/03/337163.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java多线程笔记(1)</title><link>http://www.blogjava.net/gumingcn/archive/2010/10/28/336364.html</link><dc:creator>阮步兵</dc:creator><author>阮步兵</author><pubDate>Thu, 28 Oct 2010 03:45:00 GMT</pubDate><guid>http://www.blogjava.net/gumingcn/archive/2010/10/28/336364.html</guid><wfw:comment>http://www.blogjava.net/gumingcn/comments/336364.html</wfw:comment><comments>http://www.blogjava.net/gumingcn/archive/2010/10/28/336364.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gumingcn/comments/commentRss/336364.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gumingcn/services/trackbacks/336364.html</trackback:ping><description><![CDATA[<div class="entry">
<p>1.迭代问题</p>
<p>&nbsp; 多线程环境下，迭代容易引起问题，如</p>
<p>&nbsp; for(int i=0;i&lt;v.size();i++){System.out.println(v.get(i))}</p>
<p>&nbsp;解决办法之一：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 客户端加锁</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0;true;i++){</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Sychronzied(v){</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(i&lt;v.size()){</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(v.get(i)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>}，当然这种也有问题，一旦程序可以重新设置元素位置，也会出错。</p>
<p>幸好有一种比较安全的办法： copy遍历对象</p>
<p>&nbsp;&nbsp; Sychronzied(v){</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object v_clone= copy(v);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; iterateV(v_clone);</p>
<p>2.Singleton</p>
<p>&nbsp;&nbsp; 单例习惯的方式，采用延时初始化，</p>
<p>&nbsp;&nbsp; public static A getInstance(){</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(null==instance){</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; instance=new A();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return instance</p>
<p>&nbsp;&nbsp; }</p>
<p>&nbsp; 在多线程模式下，需要加锁，来保证同步Sychronized(object){}。</p>
<p>如果初始化对象并不占用太多资源，其实没有必要加锁，毕竟同步也是很耗资源的。取消延时初始化，priavte static final instance=new A();</p>
<p>3.顺序化资源</p>
<p>&nbsp;&nbsp; 顺序化资源是避免死锁的简单的方式。</p>
<p>&nbsp;&nbsp; 死锁:T1时间，线程A 拥有objA的锁，请求objB的锁。线程B拥有objB的锁，请求objA的锁。</p>
<p>&nbsp;如： System.identityHashCode(objA)&lt;System.identityHashCode(objB)</p>
<p>&nbsp;或者：public sychronized add(A a){sychronized(a){//do something}}</p>
<p>4.wait and notify</p>
<div class="excerpt">为了防止等待-通知机制出现race condition,需要加sychronized
<p>race condition：objA在被wait之前已经被另一线程objB 给notify 了, 之后的wait 会永久停止,并导致deadlock(死锁)，当然，如果你确认可以控制wait-notify很好,就不需要加了</p>
</div>
</div>
<img src ="http://www.blogjava.net/gumingcn/aggbug/336364.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gumingcn/" target="_blank">阮步兵</a> 2010-10-28 11:45 <a href="http://www.blogjava.net/gumingcn/archive/2010/10/28/336364.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>J2EE应用安全性总结</title><link>http://www.blogjava.net/gumingcn/archive/2010/09/27/332977.html</link><dc:creator>阮步兵</dc:creator><author>阮步兵</author><pubDate>Mon, 27 Sep 2010 03:52:00 GMT</pubDate><guid>http://www.blogjava.net/gumingcn/archive/2010/09/27/332977.html</guid><wfw:comment>http://www.blogjava.net/gumingcn/comments/332977.html</wfw:comment><comments>http://www.blogjava.net/gumingcn/archive/2010/09/27/332977.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gumingcn/comments/commentRss/332977.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gumingcn/services/trackbacks/332977.html</trackback:ping><description><![CDATA[<strong>1.J2EE安全性介绍<br />
</strong>
<font><font size="2"><span style="font-size: 12pt;"><font><font size="2"><span style="font-size: 14pt;"><span style="font-size: 12pt;"><font><font size="2"><span style="font-size: 18pt;"><span style="font-size: 18pt;"><span style="font-size: 12pt;"><font><font size="2"></font></font></span></span></span></font></font></span></span></font></font></span></font></font><br />
<p><strong><span style="font-size: 12pt;">说明性的安全性：</span></strong>通过安全结构描述的方式来代表应用程序的安全需求，安全结构一般包括安全角色，访问控制和验证要求等。在j2ee平台中部署描述符充
当了说明的安全性的主要工具。部署描述符是组件开发者和应用程序部署者或应用程序组装者之间的交流工具。应用程序的开发者用它来表示应用中的安全需求，应用程序部署者或应用程序组装者将安全角色与部署环境中的用户和组映射起来。</p>
<p>在程序运行时容器从部署描述符中提取出相应的安全策略，然后容器根据安全策略执行安全验证。说明的安全性不需要开发人员编写任何安全相关的代码，一切都是通过配置部署描述符来完成的。</p>
<p><strong><span style="font-size: 12pt;">可编程的安全性:</span> </strong>可编程的安全性在说明性的安全性的基础上，使安全敏感的应用可以通过调用被容器提供的API来对安全作出决断。这在说明性的安全性不足以满足企业的安全模型的情况是非常有用的。比如J2ee在servlet HttpServletRequest interface中各提供两个方法：<br />
isUserInRole (HttpServletRequest)——判断用户角色<br />
getUserPrincipal (HttpServletRequest) ——获得用户认证信息principal<br />
另外，就是用户自定义登录认证，而不是使用J2EE的部署描述符里面的定义(三种登录认证类型)。<br />
</p>
<font><font size="2"><span style="font-size: 12pt;"><font><font size="2"><span style="font-size: 14pt;"><span style="font-size: 12pt;"><font><font size="2"><span style="font-size: 18pt;"><span style="font-size: 18pt;"><span style="font-size: 12pt;"><font><font size="2"></font></font></span></span></span></font></font></span></span></font></font></span></font></font><strong>2.基于J2<font size="2">EE的</font></strong><font><font size="2"><span style="font-size: 12pt;"><font><font size="2"><span style="font-size: 14pt;"><span style="font-size: 12pt;"><font><font size="2"><span style="font-size: 18pt;"><span style="font-size: 18pt;"><span style="font-size: 12pt;"><font><font size="2"><span style="font-size: 14pt;"><span style="font-size: 12pt;"><font><font size="2"><span style="font-size: 18pt;"><span style="font-size: 12pt;"><strong>认证与授权</strong><br />
<br />
</span></span></font></font></span></span></font></font></span></span></span></font></font></span></span></font></font></span></font></font><font><font size="2"><span style="font-size: 12pt;"><font><font size="2"><span style="font-size: 14pt;"><span style="font-size: 12pt;"><font><font size="2"><span style="font-size: 18pt;"><span style="font-size: 18pt;"><span style="font-size: 12pt;"><font><font size="2"><span style="font-size: 14pt;"><span style="font-size: 12pt;"><font><font size="2"><span style="font-size: 18pt;"><span style="font-size: 12pt;">提到安全性，就不能不说到两个概念：认证与授权。</span></span><br />
<br />
认证是用户或计算设备用来验证身份的过程。授权是根据请求用户的身份允许访问和操作一段敏感软件的过程。
这两个概念密不可分。没有授权，
就无需知道用户的身份。没能认证，就不可能区分可信和不可信用户，
更不可能安全地授权访问许多系统部分。</font></font></span></span></font></font></span><span style="font-size: 12pt;"><font size="2"></font><br />
</span></span></span></font></font></span></span></font></font></span><span style="font-size: 12pt;"><br />
因为之前的项目100% web方式，所以本文只讨论web应用的认证和授权。</span></font></font><br />
<br />
<strong>A.认证方式：</strong><br />
Web客户端通常通过http协议来请求web服务器端的资源，这些web资源通常包括html网页、jsp（java server
page）文件、java
servlet和其他一些二进制或多媒体文件。在企业环境中，企业的某些资源往往要求只允许某些人访问，有些资源甚至是机密的或安全敏感的。因此对企业中
各种web资源进行访问控制是十分必要的。为了满足企业中的不同安全级别和客户化的需求，J2EE提供了三种基于web客户端的认证方式：<br />
<br />
<p>
<strong>HTTP基本</strong><strong>认</strong><strong>证（HTTP Basic Authentication）</strong>
<br />
HTTP基本验证
是HTTP协议所支持的验证机制。这种验证机制使用用户的用户名和密码作为验证信息。Web客户端从用户获取用户名和密码，然后传递他们给web服务
器，web服务器在指定的区域（realm）中验证用户。但需要注意的是，这种验证方法是不够安全的。因为这种验证方法并不对用户密码进行加密，而只是对密码进行基本的base64的编码。而且目标web服务器对用户来说也是非验证过的。不能保证用户访问到的web服务器就是用户希望访问的。</p>
<p>
<strong>基于表单的</strong><strong>认</strong><strong>证（Form-Based Authentication）</strong>
<br />
基于表单的验证
使系统开发者可以自定义用户的登陆页面和报错页面。这种验证方法与基本HTTP的验证方法的唯一区别就在于它可以根据用户的要求制定登陆和出错页面。基于
表单的验证方法同样具有与基本HTTP验证类似的不安全的弱点。用户在表单中填写用户名和密码，而后密码以明文形式在网路中传递，如果在网路的某一节点将
此验证请求截获，在经过反编码很容易就可以获取用户的密码。因此在使用基本HTTP的验证方式和基于表单的验证方法时，一定确定这两种方式的弱点对你的应
用是可接受的。
</p>
<p>
<strong>基于客户端证书的</strong><strong>认</strong><strong>证（Client-Certificate Authentication）</strong>
<br />
基于客户端证书的验证方式要比上面两种方式更安全。它通过HTTPS（HTTP over SSL）来保证验证的安全性。安全套接层（Secure
Sockets
Layer）为验证过程提供了数据加密，服务器端认证，信息真实性等方面的安全保证。在此验证方式中，客户端必须提供一个公钥证书，你可以把这个公钥证书
看作是你的数字护照。公钥证书也称数字证书，它是被称作证书授权机构（CA）－一个被信任的组织颁发的。这个数字证书必须符合X509公钥体系结构
（PKI）的标准。如果你指定了这种验证方式，Web服务器将使用客户端提供的数字证书来验证用户的身份。&nbsp;</p>
<p><strong>B.授权模型：</strong></p>
<p><strong>代码授权（Code Authorization）</strong>
<br />
j2ee产品通过java 2 安全模型来限制特定J2SE的类和方法的执行，以保护和确保操作系统的安全。</p>
<p>
<strong>调用者授权（Caller Authorization）</strong> ——这个是我们常用的方式<br />
安全角色：安全角色是具有相同安全属性的逻辑组。比如是admin,Supervisor等。</p>
<p>
用户和组：用户和组是在实际系统环境下的用户和用户的集合。它们对应者现实当中的人和群体。
</p>
<p>
访问控制：访问控制可以确保安全角色只能访问已授予它安全权限的授权对象。授权对象包括EJB的远程方法、web资源（html网页，jsp/servlet和多媒体或二进制文件）等。在j2ee中访问控制在应用程序描述文件中与安全角色关联起来。
</p>
<p>
映射：通过映射应用程序的系统管理员将实际系统环境中的用户与安全角色联系起来，从而是实际的用户拥有对企业资源访问的适当授权。&nbsp;</p>
<p><br />
</p>
<p><strong>C.部署描述符安全性相关介绍：</strong></p>
<pre class="displaycode">安全约束——定义那些资源是受约束访问的，以及认证通过后的授权范围</pre>
<pre class="displaycode">&lt;security-constraint&gt;                                //安全约束部分
&lt;web-resource-collection&gt;                         //受约束的web资源集
&lt;web-resource-name&gt;WRCollection&lt;/web-resource-name&gt;  //资源集名
&lt;url-pattern&gt;/webtest.jsp&lt;/url-pattern&gt;                  //资源的url表达式
&lt;http-method&gt;GET&lt;/http-method&gt;                     //受约束的资源操作方法
&lt;http-method&gt;POST&lt;/http-method&gt;
&lt;/web-resource-collection&gt;
&lt;auth-constraint&gt;                                    //对安全角色授权
&lt;role-name&gt;user&lt;/role-name&gt;                        //安全角色名
&lt;/auth-constraint&gt;
&lt;user-data-constraint&gt;
&lt;transport-guarantee&gt;NONE&lt;/transport-guarantee&gt;
&lt;/user-data-constraint&gt;
&lt;/security-constraint&gt;<br />
定义安全角色
&lt;security-role&gt;
&lt;description&gt;this is a user&lt;/description&gt;
&lt;role-name&gt;user&lt;/role-name&gt;
&lt;/security-role&gt;
<br />
基本的HTTP认证方式——使用不多<br />
&lt;login-config&gt;                                        //验证方式设置
&lt;auth-method&gt;BASIC&lt;/auth-method&gt;                   //使用基本的HTTP验证方式
&lt;realm-name&gt;&lt;/realm-name&gt;
&lt;/login-config&gt;
<br />
基于表单的认证方式——使用较多<br />
&lt;login-config&gt;
&lt;auth-method&gt;FORM&lt;/auth-method&gt;                   //使用基于表单的验证方式
&lt;realm-name&gt;Default&lt;/realm-name&gt;                    //使用缺省的安全域
&lt;form-login-config&gt;
&lt;form-login-page&gt;/login.html&lt;/form-login-page&gt;        //定义登陆页面
&lt;form-error-page&gt;/error.html&lt;/form-error-page&gt;       //定义出错页面
&lt;/form-login-config&gt;
&lt;/login-config&gt;<br />
基于证书的认证方式——与CA用户数据中心一起使用<br />
&lt;login-config&gt;
&lt;auth-method&gt;CLIENT-CERT&lt;/auth-method&gt;<br />
&lt;/login-config&gt;<br />
注：后两种均在项目中应用过。<br />
以上三种认证方式都属于配置式登录认证。<br />
还有一种是程序性(编程式)的登录认证，即通过web application自身进行验证，比较典型的是利用过滤器代理操作。<br />
比如开源的acegi，使用它你将无需再web.xml里配置如此多的东西(当然，也多了许多acegi的配置)。<br />
<br />
</pre>
参考 http://www.ibm.com/developerworks/cn/java/l-j2eeSecurity/<br />
&nbsp;&nbsp;&nbsp;&nbsp; 企业级Java安全性——构建安全的J2EE应用<br />
<p>
</p>
<img src ="http://www.blogjava.net/gumingcn/aggbug/332977.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gumingcn/" target="_blank">阮步兵</a> 2010-09-27 11:52 <a href="http://www.blogjava.net/gumingcn/archive/2010/09/27/332977.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java之ThreadPool应用</title><link>http://www.blogjava.net/gumingcn/archive/2010/08/31/330457.html</link><dc:creator>阮步兵</dc:creator><author>阮步兵</author><pubDate>Tue, 31 Aug 2010 13:37:00 GMT</pubDate><guid>http://www.blogjava.net/gumingcn/archive/2010/08/31/330457.html</guid><wfw:comment>http://www.blogjava.net/gumingcn/comments/330457.html</wfw:comment><comments>http://www.blogjava.net/gumingcn/archive/2010/08/31/330457.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gumingcn/comments/commentRss/330457.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gumingcn/services/trackbacks/330457.html</trackback:ping><description><![CDATA[<p><strong>1.类介绍：<br />
Executor</strong>接口提供一种将任务提交与每个任务将如何运行的机制（包括线程使用的细节、调度等）分离开来的方法。<br />
它只有一个方法excute(Runnable command),你可以复写此方法，让Runnable同步或异步执行<br />
<strong>ExecutorService</strong>是<strong>Executor</strong>的一个子接口，提供了管理线程的方法，可为跟踪一个或多个异步任务执行状况而生成 Future 的方法。<br />
<strong>ThreadPoolExecutor</strong>是ExecutorService的一个实现类，它通常与Executors工厂一起使用。<br />
下面的方法取自Executors类<br />
public static ExecutorService newFixedThreadPool(int nThreads) {<br />
return new ThreadPoolExecutor(nThreads, nThreads,<br />
0L, TimeUnit.MILLISECONDS,<br />
new LinkedBlockingQueue&lt;Runnable&gt;());<br />
}<br />
这里面使用ThreadPoolExecutor创建一个线程数为nThreads的线程池。<br />
类似的工厂方法还有很多，可以查看JDK<br />
<strong>ExecutorService</strong>的常用方法：<br />
invokeAll 执行所有任务,全部执行完毕后返回每个任务的结果(FutureList),包括每个任务的状态<br />
invokeAny 与上面方法的区别是，只返回一个任务成功执行结果Future<br />
submit 提交一个Task去执行，并返回执行结果<br />
awaitTermination 当执行线程中断、超时，或调用了shutdown方法后，阻塞直到所有的Task都执行结束。<br />
shutdown  关闭所有执行过的Task,并不再接收新线程<br />
isTerminated 如果所有Task都关闭则返回True,前提是调用过shutdown或shutdownNow<br />
<strong>2.使用示例：</strong><br />
a.首先定义一个辅助类SystemConstant，大致方法如下：<br />
//初始化一个线程池<br />
public static ExecutorService getExecutor() {<br />
if(PROCESS_EXECUTOR == null || PROCESS_EXECUTOR.isTerminated()) {<br />
PROCESS_EXECUTOR = Executors.newFixedThreadPool(EXECUTOR_SIZE);<br />
}<br />
return PV_PROCESS_EXECUTOR;<br />
}<br />
//定义关闭方法<br />
public static void awaitTerminationExecutor(long timeout, TimeUnit unit) {<br />
getExecutor().shutdown();<br />
try {<br />
getExecutor().awaitTermination(timeout, unit);<br />
} catch (InterruptedException e) {<br />
e.printStackTrace();<br />
}<br />
}<br />
<strong> </strong>b.接下来是调用：<br />
try {<br />
SystemConstant.getExecutor().invokeAll(SystemUtils.toCallable(<br />
new SystemUtils.CallableHandle&lt;IPvProcess&gt;() {</p>
<p>public void handle(Process process) throws Exception {<br />
process.processLogs(logs, statDate);<br />
}</p>
<p>}, prepareProcesses), perOutOfTime, TimeUnit.HOURS);<br />
} catch (Exception e) {<br />
logger.error(e);<br />
}<br />
SystemConstant.awaitTerminationProgramExecutor(allOutOfTime, TimeUnit.HOURS);</p>
<p><strong>3. 类结构图</strong></p>
<p><span>java.util.concurrent</span><br />
Class ThreadPoolExecutor</p>
<pre><a title="class in java.lang" href="http://download.oracle.com/javase/1.5.0/docs/api/java/lang/Object.html">java.lang.Object</a><br />
<img src="http://download.oracle.com/javase/1.5.0/docs/api/resources/inherit.gif" alt="extended by " /><a title="class in java.util.concurrent" href="http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/AbstractExecutorService.html">java.util.concurrent.AbstractExecutorService</a><br />
<img src="http://download.oracle.com/javase/1.5.0/docs/api/resources/inherit.gif" alt="extended by " /><strong>java.util.concurrent.ThreadPoolExecutor</strong><br />
</pre>
<dl><dt><strong>All Implemented Interfaces:</strong> </dt><dd><a title="interface in java.util.concurrent" href="http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Executor.html">Executor</a>, <a title="interface in java.util.concurrent" href="http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ExecutorService.html">ExecutorService</a></dd></dl> <dl><dt><strong>Direct Known Subclasses:</strong> </dt><dd><a title="class in java.util.concurrent" href="http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html">ScheduledThreadPoolExecutor</a></dd></dl>
<img src ="http://www.blogjava.net/gumingcn/aggbug/330457.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gumingcn/" target="_blank">阮步兵</a> 2010-08-31 21:37 <a href="http://www.blogjava.net/gumingcn/archive/2010/08/31/330457.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 脚本解释器</title><link>http://www.blogjava.net/gumingcn/archive/2010/08/30/330340.html</link><dc:creator>阮步兵</dc:creator><author>阮步兵</author><pubDate>Mon, 30 Aug 2010 14:29:00 GMT</pubDate><guid>http://www.blogjava.net/gumingcn/archive/2010/08/30/330340.html</guid><wfw:comment>http://www.blogjava.net/gumingcn/comments/330340.html</wfw:comment><comments>http://www.blogjava.net/gumingcn/archive/2010/08/30/330340.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gumingcn/comments/commentRss/330340.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gumingcn/services/trackbacks/330340.html</trackback:ping><description><![CDATA[<div class="entry">
<p>如果用过python，就知道它有了command line 工具，比如你输入 print 'a' ,该工具输出:a，好处是便于快速学习python 语法。</p>
<p>其实java也可以做到。</p>
<p>下面是一个java 脚本解释器的helloword版本,思路如下：</p>
<p>1动态创建一个Temp.java类文件，里面只有一个excute方法，把从控制台输入 的字符串加入到类方法中，比如for(int i=0;i&lt;10;i++){System.out.println(i);}。</p>
<p>2再利用com.sun.tools.javac.Main.compile 动态编译Temp.java 生成class</p>
<p>3将Temp.class载入到jvm</p>
<p>4生成object实例，利用反射执行excute方法</p>
<p>说明，这只是个test版本。</p>
<p>public class Test {<br />
&nbsp;&nbsp; public static void main(String[] args)
throws IOException, ClassNotFoundException, InstantiationException,
IllegalAccessException, IllegalArgumentException, SecurityException,
InvocationTargetException, NoSuchMethodException{<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; BufferedReader reader&nbsp; = new BufferedReader(new InputStreamReader(System.in));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while(true){<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; String js=reader.readLine();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; OutputStream os = new FileOutputStream("Temp.java");&nbsp; <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; String tempJava="public class Temp"+<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; " {&nbsp;&nbsp; "+<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; " public void excute() "+<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; " {&nbsp; "+<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; js+<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; " }&nbsp; "+<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; " }&nbsp; ";<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; os.write(tempJava.getBytes());&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; os.close();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; String[] compileArgs = new String[] {"Temp.java"};&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; com.sun.tools.javac.Main.compile(compileArgs);&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; URLClassLoader loader =&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new URLClassLoader(new URL[]{new File(".").toURI().toURL()});&nbsp; <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Class&lt;?&gt; scriptClass = loader.loadClass("Temp"); <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Object obj = scriptClass.newInstance();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; obj.getClass().getDeclaredMethod("excute").invoke(obj);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; obj=null;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp; }<br />
}</p>
</div>
<img src ="http://www.blogjava.net/gumingcn/aggbug/330340.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gumingcn/" target="_blank">阮步兵</a> 2010-08-30 22:29 <a href="http://www.blogjava.net/gumingcn/archive/2010/08/30/330340.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]Effective Java总结</title><link>http://www.blogjava.net/gumingcn/archive/2010/02/27/314070.html</link><dc:creator>阮步兵</dc:creator><author>阮步兵</author><pubDate>Sat, 27 Feb 2010 07:38:00 GMT</pubDate><guid>http://www.blogjava.net/gumingcn/archive/2010/02/27/314070.html</guid><wfw:comment>http://www.blogjava.net/gumingcn/comments/314070.html</wfw:comment><comments>http://www.blogjava.net/gumingcn/archive/2010/02/27/314070.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gumingcn/comments/commentRss/314070.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gumingcn/services/trackbacks/314070.html</trackback:ping><description><![CDATA[1.使用静态工厂方法构造对象<br />
2.Boolean.valueOf()
即是1的实现，类似的还有collection集合的实例化，所有的集合实现类都是通过collection的静态工厂方法构造的。<br />
3.静态工厂
方法比构造函数的好处：可以构建原类型的子类.不一定每次都创建新的对象。缺点：静态/如果工厂方法不是公有则不能被子类继承<br />
4.注意销毁过期的
对象.array=null<br />
5.对于函数里需要构建复杂的对象时需要注意，是否可以放到类的成员变量，这样就不必每次调用该函数都创建新的复杂对
象<br />
6.避免创建重复的对象strng a=new String("a"); ---&gt; String a="a";<br />
7.当你改写
equals时，总是要改写hashcode方法:相等的对象必须具有相同的散列码，这样在此对象与map合用的时候才不会出错<br />
8.复写
equals原则：自反性，对称性，传递性，一致性<br />
9.equals方法的参数一定要说object，方法内不要依赖不可靠资源<br />
10.
提供对象的toString方法<br />
11.实现Cloneable接口提供克隆机制：深层克隆<br />
12.接口优于抽象类<br />
13.组合优于继
承<br />
14.compareTo,Comparable接口比较<br />
15.注意方法的参数检查
<img src ="http://www.blogjava.net/gumingcn/aggbug/314070.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gumingcn/" target="_blank">阮步兵</a> 2010-02-27 15:38 <a href="http://www.blogjava.net/gumingcn/archive/2010/02/27/314070.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>