context-param 与 init-param

‘context-param&init-param’ <context-param>的作用: web.xml的配置中<context-param>配置作用 1. 启动一个WEB项目的时候,容器(如:Tomcat)会去读它的配置文件web.xml.读两个节点: </listener> 和 <context-param></context-param> 2.紧接着,容器创建一个ServletContext(上下文),这个WEB项目所有部分都将共享这个上下文. 3.容器将<context-param></context-param>转化为键值对,并交给ServletContext. 4.容器创建</listener>中的类实例,即创建监听. 5.在监听中会有contextInitialized(ServletContextEvent args)初始化方法,在这个方法中获得ServletContext = ServletContextEvent.getServletContext(); context-param的值 = ServletContext.getInitParameter(“context-param的键”); 6.得到这个context-param的值之后,你就可以做一些操作了.注意,这个时候你的WEB项目还没有完全启动完成.这个动作会比所有的Servlet都要早. 换句话说,这个时候,你对<context-param>中的键值做的操作,将在你的WEB项目完全启动之前被执行. 7.举例.你可能想在项目启动之前就打开数据库. 那么这里就可以在<context-param>中设置数据库的连接方式,在监听类中初始化数据库的连接. 8.这个监听是自己写的一个类,除了初始化方法,它还有销毁方法.用于关闭应用前释放资源.比如说数据库连接的关闭. web.xml里面可以定义两种参数: (1)application范围内的参数,存放在servletcontext中,在web.xml中配置如下: <context-param> <param-name>context/param</param-name> <param-value>avalible during application</param-value> </context-param> <context-param> <param-name>cpn</param-name> <param-value>cpv</param-value> </context-param> (2)servlet范围内的参数,只能在servlet的init()方法中取得,在web.xml中配置如下: <servlet> <servlet-name>MainServlet</servlet-name> <servlet-class>com.wes.controller.MainServlet</servlet-class> <init-param> <param-name>param1</param-name> <param-value>avalible in servlet init()</param-value> </init-param> <load-on-startup>0</load-on-startup> </servlet> 在servlet中可以通过代码分别取用: package com.wes.controller; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; public class MainServlet extends HttpServlet { public MainServlet() { super(); } public void init() throws ServletException { System.out.println("下面的两个参数param1是在servlet中存放的"); System.out.println(this.getInitParameter("param1")); System.out.println("下面的参数是存放在servletcontext中的"); System.out.println(getServletContext().getInitParameter("context/param")); } } 第一种参数在servlet里面可以通过getServletContext().getInitParameter(“context/param”)得到 ...

Created 10106-06-10 · Updated 9096-10-09 · 1 min · 101 words · -

Servlet Filter

Servlet Filter @Servlet里的过滤器的主要作用 1,判断用户是否登录。 2,网络聊天系统或论坛,功能是过滤非法文字 3,统一解决编码 @Servlet3.0之前怎么创建一个过滤器 1,生成一个普通的class类,实现Filter接口(javax.servlet.Filter)。 2,重写接口里面的三个方法: init,doFilter,destroy。 其中的doFilter方法的第一个参数为ServletRequest对象。此对象给过滤器提供了对进入的信息 (包括表单数据、cookie和HTTP请求头) 的完全访问。第二个参数为ServletResponse,通常在简单的过滤器中忽略此参数。最后一个参数为FilterChain,此参数用来调用servlet或JSP页。 3,然后在web.xml配置过滤器。 具体例子:1.首先写一个权限过滤filter类,实现Filter接口 import javax.servlet.Filter; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.FilterChain; import java.io.IOException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpServletResponse; public class RightFilter implements Filter { public void init(FilterConfig filterConfig) throws ServletException { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; //如果处理HTTP请求,并且需要访问诸如getHeader或getCookies等在ServletRequest中无法得到的方法 //就要把此request对象构造成HttpServletRequest HttpServletResponse res = (HttpServletResponse) response; HttpSession session = req.getSession(true); //从session里取的用户名信息 String username = (String) session.getAttribute("username"); //判断如果没有取到用户信息,就跳转到登陆页面 if (username == null || "".equals(username)) { //跳转到登陆页面 res.sendRedirect("http://"+req.getHeader("Host")+"/login.jsp"); } else { //已经登陆,继续此次请求 chain.doFilter(request,response); //调用FilterChain对象的doFilter方法 //Filter接口的doFilter方法取一个FilterChain对象作为它的一个参数 //在调用此对象的doFilter方法时,激活下一个相关的过滤器 //如果没有另一个过滤器与servlet或JSP页面关联,则servlet或JSP页面被激活 } } public void destroy() { } } 2.然后在web.xml里配置需要登陆权限验证的JSP文件: ...

Created 10106-06-10 · Updated 9096-10-09 · 5 min · 1056 words · -

web service

web service http://www.cnblogs.com/hanlsheng/archive/2011/01/20/1940367.html 第一章 设计一个简单的web service接口 本章主要内容: 你将学会如何设计一个简单的web service接口 穿越网络提供跨平台操作 假设你想为大众或者业务伙伴提供一种这样的服务: 他们向你发送两个字符串,你把两个字符串进行连接,然后返回给他们。当然在现实世界中,你将提供一些更有用更复杂的服务。 此服务有几个必须满足的需求: 首先,用户可以使用不同的语言( 比如Java,C# 等)以及不同的平台( Windows,Linux等)。你提供的服务对于不同的语言和平台必须是可以访问的。第二,用户可以通过网络对你的服务进行访问。而且必须能够穿越防火墙。 给定了以上需求,最佳的解决方案是提供一个所谓的"web service"。比如,你可以在主机( www.ttdev.com)上提供可访问的web service( 通过/SimpleService 访问,见下图),所以URL全称是: http: www.ttdev.com/SimpleService. 这被称为web service的"endpoint"( 终端,端点)。web service 可以支持一个或者多个操作。在这个例子中,一个操作被命名为"concat": 然而,你希望为你的每一个web service 操作提供全球唯一标识,这样别人也可以拥有名称为"concat"的操作。如何实现呢?很简单,你可以在名称"concat"前面声明一个"namespace"( 命名空间,比如http: ttdev.com/ss). namespace( 命名空间)的作用同java 中包的作用非常类似,只是表示形式不用而已,包的表示形式为 com.ttdev.foo。全球唯一标识是由namespace和操作名称组成的。Operation(操作)的名称,比如"concat"被称为local name( 本地名称)。全球唯一标识被称为QName( qualified name)。 你可能想知道命名空间(如http: ttdev.com/ss)有什么含义。答案是:没有什么特别的含义。即使这个命名空间是一个URL,但不意味着你能通过浏览器进行访问会获得一个可访问页面。对你来说唯一重要的一点是,这个标识是全球唯一的。因为我已经注册了这个域名ttdev.com,所以它一定是全球唯一的。 值得注意的一点是, namespace (命名空间)与endpoint(终端,端点)是完全不同的概念。endpoint是真实的服务提供地点,而namespace仅仅是一个唯一标识符号。我可以轻易的把服务部署在另外的服务器上,这样web service将会有不同的 endpoint,但是 web service的操作唯一标识( 命名空间+本地名称)可以保持不变。 2.RPC 类型的web service 你的concat 操作将包含两个参数。一个名称为"s1"为string 类型。另一个名称为"s2"同样是string类型。返回值同样是一个string类型: 然而,上图中的string 类型是什么含义呢?是Java的 string类型吗?不是,因为它必须是语言中立的。幸运的是,XML schema spec 定义了一些基本的数据类型,其中包括string类型。每一个数据类型都有一个QName 作为其id。比如: 所以操作的接口可以如下表示: ...

Created 17176-06-17 · Updated 9096-10-09 · 2 min · 327 words · -

ServletContextListener

ServletContextListener http://www.cnblogs.com/kentyshang/archive/2007/06/26/795878.html ServletContextListener处理Web应用的 servlet上下文(context)的变化的通知。这可以解释为,好像有个人在服务器旁不断地通知我们服务器在发生什么事件。那当然需要监听者了。因 此,在通知上下文(context)初始化和销毁的时候,ServletContextListner非常有用。 import javax.servlet.ServletContextListener; import javax.servlet.ServletContextEvent; import javax.servlet.*; public class MyListener implements ServletContextListener { private ServletContext context = null; /* 这个方法在Web应用服务被移除,没有能力再接受请求的时候被调用。 */ public void contextDestroyed(ServletContextEvent event){ //Output a simple message to the server's console System.out.println("The Simple Web App. Has Been Removed"); this.context = null; } // 这个方法在Web应用服务做好接受请求的时候被调用。 public void contextInitialized(ServletContextEvent event){ this.context = event.getServletContext(); //Output a simple message to the server's console System.out.println("The Simple Web App. Is Ready"); } } <web-app> <listener> <listener-class> com.listeners.MyContextListener </listener-class> </listener> <servlet/> <servlet-mapping/> </web-app> —————————————-转载http://blog.csdn.net/ezerg/archive/2004/09/24/115894.aspx ...

Created 22226-06-22 · Updated 9096-10-09 · 1 min · 210 words · -

ReentrantLock,互斥锁,重入锁

ReentrantLock,互斥锁,重入锁 在并发编程中,多线程同时并发访问的资源叫做临界资源,当多个线程同时访问对象并要求操作相同资源时,分割了原子操作就有可能出现数据的不一致或数据不完整的情况,为避免这种情况的发生,我们会采取同步机制,以确保在某一时刻,方法内只允许有一个线程。 synchronized 采用 synchronized 修饰符实现的同步机制叫做互斥锁机制,它所获得的锁叫做互斥锁。每个对象都有一个 monitor (锁标记),当线程拥有这个锁标记时才能访问这个资源,没有锁标记便进入锁池。任何一个对象系统都会为其创建一个互斥锁,这个锁是为了分配给线程的,防止打断原子操作。每个对象的锁只能分配给一个线程,因此叫做互斥锁。 这里就使用同步机制获取互斥锁的情况,进行几点说明: 如果同一个方法内同时有两个或更多线程,则每个线程有自己的局部变量拷贝。 类的每个实例都有自己的对象级别锁。当一个线程访问实例对象中的 synchronized 同步代码块或同步方法时,该线程便获取了该实例的对象级别锁,其他线程这时如果要访问 synchronized 同步代码块或同步方法,便需要阻塞等待,直到前面的线程从同步代码块或方法中退出,释放掉了该对象级别锁。 访问同一个类的不同实例对象中的同步代码块,不存在阻塞等待获取对象锁的问题,因为它们获取的是各自实例的对象级别锁,相互之间没有影响。 持有一个对象级别锁不会阻止该线程被交换出来,也不会阻塞其他线程访问同一示例对象中的非synchronized代码。当一个线程A持有一个对象级别锁 (即进入了 synchronized 修饰的代码块或方法中) 时,线程也有可能被交换出去,此时线程B有可能获取执行该对象中代码的时间,但它只能执行非同步代码 (没有用synchronized修饰) ,当执行到同步代码时,便会被阻塞,此时可能线程规划器又让A线程运行,A线程继续持有对象级别锁,当A线程退出同步代码时 (即释放了对象级别锁) ,如果B线程此时再运行,便会获得该对象级别锁,从而执行synchronized中的代码。 持有对象级别锁的线程会让其他线程阻塞在所有的 synchronized 代码外。例如,在一个类中有三个synchronized方法 a,b,c,当线程A正在执行一个实例对象M中的方法 a 时,它便获得了该对象级别锁,那么其他的线程在执行同一实例对象 (即对象M) 中的代码时,便会在所有的 synchronized 方法处阻塞,即在方法 a,b,c处都要被阻塞,等线程A释放掉对象级别锁时,其他的线程才可以去执行方法a,b或者c中的代码,从而获得该对象级别锁。 使用 synchronized (obj) 同步语句块,可以获取指定对象上的对象级别锁。obj为对象的引用,如果获取了obj对象上的对象级别锁,在并发访问obj对象时时,便会在其synchronized代码处阻塞等待,直到获取到该obj对象的对象级别锁。当obj为 this 时,便是获取当前对象的对象级别锁。 类级别锁被特定类的所有示例共享,它用于控制对static成员变量以及static方法的并发访问。具体用法与对象级别锁相似。 互斥是实现同步的一种手段,临界区、互斥量和信号量都是主要的互斥实现方式. synchronized 关键字经过编译后,会在同步块的前后分别形成 monitorenter 和 monitorexit 这两个字节码指令。根据虚拟机规范的要求,在执行 monitorenter 指令时,首先要尝试获取对象的锁,如果获得了锁,把锁的计数器加1,相应地,在执行 monitorexit 指令时会将锁计数器减1,当计数器为0时,锁便被释放了。由于synchronized 同步块对同一个线程是可重入的,因此一个线程可以多次获得同一个对象的互斥锁,同样,要释放相应次数的该互斥锁,才能最终释放掉该锁。 synchronized 是非公平锁 (TODO: 需要测试,没重现成功…) https://blog.csdn.net/FU250/article/details/106640613 ReentrantLock ReentrantLock 是一个可重入的互斥锁,又被称为"独占锁"。ReentrantLock 的实现不仅可以替代隐式的 synchronized 关键字,而且能够提供超过关键字本身的多种功能。 而锁的名字也是说明了这个锁具备了重复进入的可能,也就是说能够让当前线程多次的进行对锁的获取操作,这样的最大次数限制是 Integer.MAX_VALUE,约 21 亿次左右。 ...

Created 8086-07-08 · Updated 9096-10-09 · 5 min · 894 words · -

Java 正则表达式分组与捕获

JAVA 正则表达式 分组与捕获 import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Fenzhu { public static void main(String[] args) { Pattern p = Pattern.compile("(/d{3,5})([a-z]{2})"); String s = "123aa-34345bb-234cc-00"; Matcher m = p.matcher(s); while(m.find()) { System.out.println("m.group():"+m.group()); //打印所有 System.out.println("m.group(1):"+m.group(1)); //打印数字的 System.out.println("m.group(2):"+m.group(2)); //打印字母的 System.out.println(); } System.out.println("捕获个数:groupCount()="+m.groupCount()); } } 1 概述 1.1 什么是捕获组 捕获组就是把正则表达式中子表达式匹配的内容,保存到内存中以数字编号或显式命名的组里,方便后面引用。当然,这种引用既可以是在正则表达式内部,也可以是在正则表达式外部。 捕获组有两种形式,一种是普通捕获组,另一种是命名捕获组,通常所说的捕获组指的是普通捕获组。语法如下: 普通捕获组: (Expression) 命名捕获组: (?<name>Expression) ...

Created 19196-08-19 · Updated 9096-10-09 · 4 min · 642 words · -

Java 线程池, thread pool, Executors, ThreadPoolExecutor

Java 线程池, thread pool, Executors, ThreadPoolExecutor Executors ThreadPoolExecutor ExecutorService 在 Java 1.5 引入 ExecutorService 之后,基本上已经不建议直接创建 Thread 对象,而是统一使用 ExecutorService。毕竟从接口的易用程度上来说 ExecutorService 就远胜于原始的 Thread,更不用提 java.util.concurrent 提供的数种线程池,Future 类,Lock 类等各种便利工具。 在操作系统中,线程是一个非常重要的资源,频繁创建和销毁线程会降低系统性能。Java 线程池原理类似于数据库连接池,目的就是帮助我们实现线程复用,减少频繁创建和销毁线程。ThreadPoolExecutor Executors Executors 提供了一些创建线程池的工具方法。 ExecutorService es = Executors.newSingleThreadExecutor() 源码实现: new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()) corePoolSize 和maximumPoolSize都为1,也就是创建了一个固定大小是1的线程池,workQueue是 new LinkedBlockingQueue<Runnable>() 也就是队列的大小是Integer.MAX_VALUE,可以认为是队列的大小不限制。 由此可以得出通过该方法创建的线程池,每次只能同时运行一个线程,当有多个任务同时提交时,那也要一个一个排队执行。 Executors.newFixedThreadPool(int nThreads) 源码实现: new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()) 类似Executors.newSingleThreadExecutor()也是创建了一个固定大小的线程池,但是可以指定同时运行的线程数量为nThreads。 Executors.newCachedThreadPool() 源码实现: new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()) corePoolSize为0,maximumPoolSize为Integer.MAX_VALUE可以视为无穷大,workQueue是一个SynchronousQueue。SynchronousQueue可以认为是一个长度限制为0的队列,也就是向这个队列添加任务会永远是已满的状态。 由此可以得出通过该方法创建的线程池并不限制线程数量,每次添加的任务都会直接执行而不会放入workQueue,它的主要提供的功能是线程复用,但不能控制线程数量。 ...

Created 26266-08-26 · Updated 9096-10-09 · 4 min · 721 words · -

ArrayBlockingQueue

ArrayBlockingQueue ArrayBlockingQueue 是一个基于数组的阻塞队列实现,此队列按 FIFO (先进先出) 原则对元素进行排序, 在 ArrayBlockingQueue 内部,维护了一个定长数组,以便缓存队列中的数据对象,这是一个常用的阻塞队列,除了一个定长数组外,ArrayBlockingQueue内部还保存着两个整形变量,分别标识着队列的头部和尾部在数组中的位置。 ArrayBlockingQueue 在生产者放入数据和消费者获取数据,都是共用同一个锁对象,由此也意味着两者无法真正并行运行,这点尤其不同于 LinkedBlockingQueue, 按照实现原理来分析 ArrayBlockingQueue 完全可以采用分离锁,从而实现生产者和消费者操作的完全并行运行。Doug Lea 之所以没这样去做,也许是因为 ArrayBlockingQueue 的数据写入和获取操作已经足够轻巧,以至于引入独立的锁机制,除了给代码带来额外的复杂性外,其在性能上完全占不到任何便宜。 ArrayBlockingQueue 和 LinkedBlockingQueue 间还有一个明显的不同之处在于,前者在插入或删除元素时不会产生或销毁任何额外的对象实例,而后者则会生成一个额外的 Node 对象。这在长时间内需要高效并发地处理大批量数据的系统中,其对于 GC 的影响还是存在一定的区别。而在创建 ArrayBlockingQueue 时,我们还可以控制对象的内部锁是否采用公平锁,默认采用非公平锁。 队列的头部是在队列中存在时间最长的元素。队列的尾部是在队列中存在时间最短的元素。新元素插入到队列的尾部,队列检索操作则是从队列头部开始获得元素。 这是一个典型的 “有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦创建了这样的缓存区,就不能再增加其容量。试图向已满队列中放入元素会导致放入操作受阻塞;试图从空队列中检索元素将导致类似阻塞。 此类支持对等待的生产者线程和使用者线程进行排序的可选公平策略。默认情况下,不保证是这种排序。然而,通过将公平性 (fairness) 设置为 true 而构造的队列允许按照 FIFO 顺序访问线程。公平性通常会降低吞吐量,但也减少了可变性和避免了"不平衡性"。 ArrayBlockingQueue 在构造时需要指定容量,并可以选择是否需要公平性,如果公平参数被设置true,等待时间最长的线程会优先得到处理 (其实就是通过将 ReentrantLock 设置为 true 来达到这种公平性的: 即等待时间最长的线程会先操作) 。通常,公平性会使你在性能上付出代价,只有在的确非常需要的时候再使用它。它是基于数组的阻塞循环队列,此队列按 FIFO (先进先出) 原则对元素进行排序。 PriorityBlockingQueue PriorityBlockingQueue 是一个带优先级的队列,而不是先进先出队列。元素按优先级顺序被移除,该队列也没有上限 (看了一下源码,PriorityBlockingQueue 是对 PriorityQueue 的再次包装,是基于堆数据结构的,而 PriorityQueue 是没有容量限制的,与ArrayList一样,所以在优先阻塞队列上put时是不会受阻的。虽然此队列逻辑上是无界的,但是由于资源被耗尽,所以试图执行添加操作可能会导致 OutOfMemoryError) ,但是如果队列为空,那么取元素的操作take就会阻塞,所以它的检索操作take是受阻的。另外,往入该队列中的元素要具有比较能力。 最后,DelayQueue (基于PriorityQueue来实现的) 是一个存放Delayed 元素的无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部是延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,并且poll将返回null。当一个元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一个小于或等于零的值时,则出现期满,poll就以移除这个元素了。此队列不允许使用 null 元素。 下面是延迟接口: ...

Created 26266-08-26 · Updated 9096-10-09 · 2 min · 386 words · -

Spring 中 bean 的作用域

Spring中bean的作用域 http://blog.csdn.net/ProvidenceZY/article/details/1878582 如何使用spring的作用域: <bean id="role" class="spring.chapter2.maryGame.Role" scope="singleton"/> 这里的scope就是用来配置spring bean的作用域,它标识bean的作用域。 在spring2.0之前bean只有2种作用域即: singleton(单例)、non-singleton (也称prototype) , Spring2.0以后,增加了session、request、global session三种专用于Web应用程序上下文的Bean。因此,默认情况下Spring2.0现在有五种类型的Bean。当然,Spring2.0对Bean的类型的设计进行了重构,并设计出灵活的Bean类型支持,理论上可以有无数多种类型的Bean,用户可以根据自己的需要,增加新的Bean类型,满足实际应用需求。 1、singleton作用域 当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。换言之,当把一个bean定义设置为singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存 (singleton cache) 中,并且所有针对该bean的后续请求和引用都将返回被缓存的对象实例,这里要注意的是singleton作用域和GOF设计模式中的单例是完全不同的,单例设计模式表示一个ClassLoader中只有一个class存在,而这里的singleton则表示一个容器对应一个bean,也就是说当一个bean被标识为singleton时候,spring的IOC容器中只会存在一个该bean。 配置实例: <bean id="role" class="spring.chapter2.maryGame.Role" scope="singleton"/> 或者 <bean id="role" class="spring.chapter2.maryGame.Role" singleton="true"/> 2、prototype prototype作用域部署的bean,每一次请求 (将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法) 都会产生一个新的bean实例,相当与一个new的操作,对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。 (让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用bean的后置处理器,该处理器持有要被清除的bean的引用。) 配置实例: <bean id="role" class="spring.chapter2.maryGame.Role" scope="prototype"/> 或者 <beanid="role" class="spring.chapter2.maryGame.Role" singleton="false"/> 3、request request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效,配置实例: request、session、global session使用的时候首先要在初始化web的web.xml中做如下配置: 如果你使用的是Servlet 2.4及以上的web容器,那么你仅需要在web应用的XML声明文件web.xml中增加下述ContextListener即可: <web-app> ... <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener> ... </web-app> 如果是Servlet2.4以前的web容器,那么你要使用一个javax.servlet.Filter的实现: <web-app> .. <filter> <filter-name>requestContextFilter</filter-name> <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class> </filter> <filter-mapping> <filter-name>requestContextFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ... </web-app> 接着既可以配置bean的作用域了: <bean id="role" class="spring.chapter2.maryGame.Role" scope="request"/> 4、session session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效,配置实例: 配置实例: ...

Created 16166-09-16 · Updated 9096-10-09 · 2 min · 218 words · -

Java Thread/线程

Java Thread/线程 java的线程是映射到操作系统原生线程之上的 java线程阻塞的代价 java的线程是映射到操作系统原生线程之上的,如果要阻塞或唤醒一个线程就需要操作系统介入,需要在户态与核心态之间切换,这种切换会消耗大量的系统资源,因为用户态与内核态都有各自专用的内存空间,专用的寄存器等,用户态切换至内核态需要传递给许多变量、参数给内核,内核也需要保护好用户态在切换时的一些寄存器值、变量等,以便内核态调用结束后切换回用户态继续工作。 如果线程状态切换是一个高频操作时,这将会消耗很多CPU处理时间; 如果对于那些需要同步的简单的代码块,获取锁挂起操作消耗的时间比用户代码执行的时间还要长,这种同步策略显然非常糟糕的。 线程状态 线程共包括以下5种状态。 新建状态 (New): 线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()。 就绪状态(Runnable): 也被称为 “可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。 运行状态(Running): 线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。 阻塞状态(Blocked): 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种: 等待阻塞 – 通过调用线程的 wait() 方法,让线程等待某工作的完成。 同步阻塞 – 线程在获取 synchronized 同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。 其他阻塞 – 通过调用线程的 sleep() 或 join() 或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。 死亡状态(Dead): 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。 这 5 种状态涉及到的内容包括 Object 类, Thread 类, 和 synchronized 关键字。 这些内容我们会在后面的章节中逐个进行学习。 Object 类,定义了 wait(), notify(), notifyAll( ) 等休眠/唤醒函数。 Thread 类,定义了一些列的线程操作函数。例如,sleep() 休眠函数, interrupt() 中断函数, getName() 获取线程名称等。 synchronized,是关键字;它区分为 synchronized 代码块和 synchronized 方法。 synchronized 的作用是让线程获取对象的同步锁。 在后面详细介绍 wait(), notify() 等方法时,我们会分析为什么 “wait(), notify() 等方法要定义在 Object 类,而不是 Thread 类中” ...

Created 22226-09-22 · Updated 9096-10-09 · 5 min · 866 words · -

Abstract Factory with Reflection 持续改进,抽象工厂也反射

持续改进,抽象工厂也反射 http://www.cnblogs.com/shenfx318/archive/2007/01/16/621237.html 在我的上一篇文章(疑惑?改良?从简单工厂到工厂方法)中,详细论述了创建模式中简单工厂到工厂方法的演变过程,并试图结合工厂方法的设计以及.net中的反射机制之所长,改良出一种新型的工厂—反射工厂,这当然不是我的首创,经典的PetShop 中便有此工厂的身影。本文尝试按照前篇文章的思路,借着工厂方法到抽象工厂的演变过程而继续对抽象工厂进行改良,文章中的思想仅代表了作者当时的观点,有欠妥的地方,还请各位不吝赐教。 工厂模式 前面的文章提到了简单工厂和工厂方法其实是一码事,他们完成了将客户对产品功能的使用与创建具体产品职责的分割,不同的只不过是他们实现方式上的差异,工厂方法利用更加优雅的多态性取代了相对ugly的switch case…语句,从而很好的体现了设计原则中的OCP原则,此文章将不再强调这种实现上的差异性,而更多的强调两者之间设计思路上的共性,并将这种共性统称成为工厂模式,从而进一步与抽象工厂进行对比。 工厂的使用,选择的过程 工厂模式的使用,实际上是客户 (产品的消费者) 对于产品选择的过程,对于实现了相同功能的产品来讲,客户更加关心的是产品间的差异性,而工厂的作用则是将产品的生产过程封装,根据客户的要求直接返回客户需要的产品。注意,工厂只是隐藏了产品的生产过程,但是并没有剥夺客户选择的权利,那么客户的这个选择过程又是如何体现的呢?在简单工厂中,客户通过参数的形式告诉工厂需要什么样的产品,而在工厂方法中,客户通过对工厂的选择代替了直接对产品的选择,注意到工厂方法中一个工厂只有一个Create方法,也就是说一个工厂只负责生产一种产品,那么你选择了相应的工厂也就等同于你选择了对应的产品。就连改良后的反射工厂也没有消去对产品的选择,只不过是将这种选择外化 (外化到配置文件中,从而使得对代码的改动最小) 。可以说,正是由于产品间的差异性带给了客户选择的权利,这种权利是不应当被工厂取代的,那么工厂模式的价值又在哪里呢?答案是抽象与封装,工厂模式将由于客户的不同选择而可能导致的对已知事物的影响降到最低,途径是通过抽象产品取代具体产品,使得客户依赖于抽象 (越抽象的东西越稳定) ,同时将客户的选择封装到一处,隔离与具体产品间的依赖。 工厂模式与抽象工厂 前面说了这么多无关的,为得是做好铺垫,更加有益于对下文的理解,OK,终于该说说从工厂模式到抽象工厂的转变了,先来对比两张类图: 工厂方法(Factory Method) ![](http://images.cnblogs.com/cnblogs_com/shenfx318/FactoryMethod3.jpg) 抽象工厂(Abstract Factory) 从图中我们能够看到哪些差异? 最明显的一点就是在工厂方法的类关系图中只有一类产品,他们实现了一个统一的接口,而抽象工厂有多个类别的产品,他们分别实现了不同的功能 (多个接口) 。其次的一点差别就是工厂本身所具有的方法数量不同,这点差异其实也是由第一点所导致的,工厂需要有生产不同类别产品的功能,如果抽象工厂中的产品的功能简化到一个,也便成为了工厂方法。 引出类别的概念,类别是指具有相同功能的一类产品的总称。 再来看选择的过程,在工厂方法中,客户关心的只不过是实现同一样功能的不同产品间的差异,这是一个一维选择的过程。 1 IFactory factory = new FactoryA(); //选择了工厂即选择了产品 2 IProduct productA = factory.Create(); //工厂只有一个Create方法,只能生产一种产品 而在抽象工厂中,客户首先要考虑的是需要哪一样功能,其次要考虑才是产品间的差异。也就是说这是一个二维选择的过程。 1 IFactory factory = new FactoryA(); //选择了某个具体工厂 2 IProduct productA = factory.CreateProductA(); //工厂具有多个Create方法,这里选择了其中的一个 由于产品类别的增加而导致客户在考虑产品间差异的同时还要考虑产品间功能的差异,这种二维选择的过程才是工厂方法与抽象工厂之间的本质区别。 举个肯德基与麦当劳的例子,假设原来只有一家快餐店叫做麦当劳,提供的食物 (具体产品) 有汉堡、可乐、薯条,它们都可以满足你吃东西 (抽象接口) 的需求,那么你想吃快餐的时候,唯一的选择就在于吃什么,是一维选择,现在又开了一家快餐店叫做肯德基,同样供应汉堡、可乐和薯条,那么现在你若打算吃快餐,除了考虑吃什么外,还要考虑去哪里吃-肯德基还是麦当劳?这便是二维的选择。通过横向与纵向的选择才能最终锁定你要的产品。 ...

Created 12126-10-12 · Updated 9096-10-09 · 1 min · 211 words · -

Filter FilterChain

Filter FilterChain **[http://blog.csdn.net/zhaozheng7758/article/details/6105749](http://blog.csdn.net/zhaozheng7758/article/details/6105749)** 一、Filter的介绍及使用**** 什么是过滤器? 与Servlet相似,过滤器是一些web应用程序组件,可以绑定到一个web应用程序中。但是与其他web应用程序组件不同的是,过滤器是"链"在容器的处理过程中的。这就意味着它们会在servlet处理器之前访问一个进入的请求,并且在外发响应信息返回到客户前访问这些响应信息。这种访问使得过滤器可以检查并修改请求和响应的内容。 过滤器适用于那些地方? l 为一个web应用程序的新功能建立模型(可被添加到web应用程序中或者从web应用程序中删除而不需要重写基层应用程序代码); l 向过去的代码添加新功能。 过滤器放在容器结构的什么位置? 过滤器放在web资源之前,可以在请求抵达它所应用的web资源(可以是一个Servlet、一个Jsp页面,甚至是一个HTML页面)之前截获进入的请求,并且在它返回到客户之前截获输出请求。Filter: 用来拦截请求,处于客户端与被请求资源之间,目的是重用代码。Filter链,在web.xml中哪个先配置,哪个就先调用。在filter中也可以配置一些初始化参数。 Java中的Filter 并不是一个标准的Servlet ,它不能处理用户请求,也不能对客户端生成响应。 主要用于对HttpServletRequest 进行预处理,也可以对HttpServletResponse 进行后处理,是个典型的处理链。 Filter 有如下几个用处: l 在HttpServletRequest 到达Servlet 之前,拦截客户的HttpServletRequest 。 l 根据需要检查HttpServletRequest ,也可以修改HttpServletRequest 头和数据。 l 在HttpServletResponse 到达客户端之前,拦截HttpServletResponse 。 l 根据需要检查HttpServletResponse ,可以修改HttpServletResponse 头和数据。 Filter 有如下几个种类: l 用户授权的Filter: Filter 负责检查用户请求,根据请求过滤用户非法请求。 l 日志Filter: 详细记录某些特殊的用户请求。 l 负责解码的Filter: 包括对非标准编码的请求解码。 l 能改变XML 内容的XSLTFilter 等。 一个Filter 可负责拦截多个请求或响应:一个请求或响应也可被多个请求拦截。 创建一个Filter 只需两个步骤: (1)创建Filter 处理类: (2)在web.xml 文件中配置Filter 。 创建Filter 必须实现javax.servlet.Filter 接口,在该接口中定义了三个方法。 • void init(FilterConfig config): 用于完成Filter 的初始化。 ...

Created 18186-11-18 · Updated 9096-10-09 · 3 min · 602 words · -

PropertyPlaceholderConfigurer

PropertyPlaceholderConfigurer http://callan.iteye.com/blog/161540 关于PropertyPlaceholderConfigurer与PropertyOverrideConfigurer PropertyPlaceholderConfigurer,允许在spring的配置文件中加入properties文件,可以将一些动态参数移到properties中. <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:config/jdoserver.properties"/> </bean> 但是好像在属性文件定义中却不支持多个属性文件的定义,比如不能这样用config/*.properties。 经过查看源码,发现可以使用locations属性定义多个配置文件: <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:config/maxid.properties</value> <value>classpath:config/jdoserver.properties</value> </list> </property> </bean> 使用外部属性后如下: <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.agent.driver}"/> <property name="url" value="${jdbc.agent.main.url}"/> </bean> PropertyOverrideConfigurer: 在spring所有的bean初使化以后,将bean的值强行改变 <bean id="configBean" class="org.springframework.beans.factory.config.PropertyOverrideConfigurer"> <property name="location"> <value>hello.properties</value> </property> </bean> <bean id="helloBean" class="com.HelloBean"> <property name="word"> <value>Hello!</value> </property> </bean> 定义HelloBean,注入word的值为hello. 在hello.properties中 helloBean.word=Welcome! word初使为hello后,当bean全加载完,PropertyOverrideConfigurer将helloBean.word的值改成为welcome. 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 8086-12-08 · Updated 9096-10-09 · 1 min · 73 words · -

resource-ref

resource-ref resource-ref元素用于指定对外部资源的servlet引用的声明。 <!ELEMENT resource-ref (description?, res-ref-name, res-type, res-auth, res-sharing-scope?)> <!ELEMENT description (#PCDATA)> <!ELEMENT res-ref-name (#PCDATA)> <!ELEMENT res-type (#PCDATA)> <!ELEMENT res-auth (#PCDATA)> <!ELEMENT res-sharing-scope (#PCDATA)> resource-ref子元素的描述如下: ● res-ref-name是资源工厂引用名的名称。该名称是一个与java:comp/env上下文相对应的JNDI名称,并且在整个Web应用中必须是惟一的。 ● res-auth表明: servlet代码通过编程注册到资源管理器,或者是容器将代表servlet注册到资源管理器。该元素的值必须为Application或Container。 ● res-sharing-scope表明: 是否可以共享通过给定资源管理器连接工厂引用获得的连接。该元素的值必须为Shareable(默认值)或Unshareable。 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 5056-01-05 · Updated 9096-10-09 · 1 min · 49 words · -

Spring Annotation @Resource

Spring Annotation @Resource Spring 不但支持自己定义的 @Autowired 的注释,还支持几个由 JSR-250 规范定义的注释,它们分别是@Resource、@PostConstruct 以及 @PreDestroy。 @Resource @Resource 的作用相当于 @Autowired,只不过 @Autowired 按 byType 自动注入,面 @Resource 默认按 byName 自动注入罢了。@Resource 有两个属性是比较重要的,分别是 name 和 type,Spring 将 @Resource 注释的 name 属性解析为 Bean 的名字,而 type 属性则解析为 Bean 的类型。所以如果使用 name 属性,则使用 byName 的自动注入策略,而使用 type 属性时则使用 byType 自动注入策略。如果既不指定 name 也不指定 type 属性,这时将通过反射机制使用 byName 自动注入策略。 @Resource装配顺序 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常 如果指定了name,则从上下文中查找名称 (id) 匹配的bean进行装配,找不到则抛出异常 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配 (见2) ;如果没有匹配,则回退为一个原始类型 (UserDao) 进行匹配,如果匹配则自动装配; Spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource、@PostConstruct以及@PreDestroy。 @Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按 byName自动注入罢了。@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。 @Resource装配顺序 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常 如果指定了name,则从上下文中查找名称 (id) 匹配的bean进行装配,找不到则抛出异常 ...

Created 16166-01-16 · Updated 9096-10-09 · 2 min · 358 words · -

利用 Spring 的 JdbcTemplate 处理 BLOB、CLOB

利用spring的jdbcTemplate处理blob、clob spring定义了一个以统一的方式操作各种数据库的Lob类型数据的LobCreator(保存的时候用),同时提供了一个LobHandler为操作二进制字段和大文本字段提供统一接口访问。 举例,例子里面的t_post表中post_text字段是CLOB类型,而post_attach是BLOG类型: public class PostJdbcDao extends JdbcDaoSupport implements PostDao { private LobHandler lobHandler; private DataFieldMaxValueIncrementer incre; public LobHandler getLobHandler() { return lobHandler; } public void setLobHandler(LobHandler lobHandler) { this.lobHandler = lobHandler; } public void addPost(final Post post) { String sql = " INSERT INTO t_post(post_id,user_id,post_text,post_attach)" + " VALUES(?,?,?,?)"; getJdbcTemplate().execute( sql, new AbstractLobCreatingPreparedStatementCallback( this.lobHandler) { protected void setValues(PreparedStatement ps, LobCreator lobCreator) throws SQLException { ps.setInt(1, incre.nextIntValue()); ps.setInt(2, post.getUserId()); lobCreator.setClobAsString(ps, 3, post.getPostText()); lobCreator.setBlobAsBytes(ps, 4, post.getPostAttach()); } }); } } 设置相对应的配置文件(Oracle 9i版本),Oracle的数据库最喜欢搞搞特别的东西啦: ...

Created 16166-01-16 · Updated 9096-10-09 · 2 min · 219 words · -

将应用部署到 Tomcat 根目录的方法

将应用部署到Tomcat根目录的方法 http://rongjih.blog.163.com/blog/static/335744612011426103345778/ 将应用部署到Tomcat根目录的目的是可以通过 http://[ip]:[port] 直接访问应用,而不是使用 http://[ip]:[port]/[appName] 上下文路径进行访问。 方法一: (最简单直接的方法) 删除原 webapps/ROOT 目录下的所有文件,将应用下的所有文件和文件夹复制到ROOT文件夹下。 方法二: 删除原 webapps/ROOT 目录下的所有文件,修改文件"conf/server.xml",在Host节点下增加如下Context的内容配置: <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false"> ...... <Context path="" docBase="C:/apache-tomcat-6.0.32/myapps/bc.war"></Context> </Host> 注意: path 的值设置为空; 应用不要放到tomcat的webapps目录下(如上述配置是放到自定义的文件夹myapps内的),否则访问时路径很有问题; docBase指定到绝对路径。 如此设置后重启tomcat,如果docBase指向的是war文件,会自动将war解压到 webapps/ROOT 目录;如果docBase指向的是应用已解压好的目录,如 docBase=“C:/apache-tomcat-6.0.32/myapps/bc”,tomcat不会生成webapps/ROOT目录 (这种情况下之前可以不用删除webapps/ROOT目录,但webapps/ROOT目录内的内容是无法访问的) ,访问时将直接使用docBase指定的目录。 方法三: 与方法二类似,但不是修改全局配置文件"conf/server.xml",而是在"conf/Catalina/localhost"目录下增加新的文件"ROOT.xml" (注意大小写哦) ,文件内容如下: <?xml version="1.0" encoding="UTF-8"?> <Context path="" docBase="C:/apache-tomcat-6.0.32/myapps/bc.war"></Context> 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码;文件重命名为 tomcat-root-deploy.md;title 改为「将应用部署到 Tomcat 根目录的方法」;url 改为 tomcat-root-deploy;旧 url 加入 aliases 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 16166-01-16 · Updated 9096-10-09 · 1 min · 74 words · -

MyBatis 多参数查询映射

Mybatis多参数查询映射 http://fengfan876.iteye.com/blog/1473863 最近在做一个Mybatis的项目,由于是接触不久,虽然看了一下资料,但在实际开发中还是暴露了很多问题,其中最让我头疼的就是selete的parameterType问题,网上这类的帖子虽然有但是不全,很多情况下很难找到你想要的答案。 为此我对这个问题进行了总结,希望对像我这样的新手有一定的帮助。 (一) 单个参数 public List<XXBean> getXXBeanList(String xxCode); <select id="getXXXBeanList" parameterType="java.lang.String" resultType="XXBean"> select 字段… from XXX where code = #{xxCode} </select> 其中方法名和ID一致,#{}中的参数名与方法中的参数名一直, 我这里采用的是XXXBean是采用的短名字, select 后的字段列表要和bean中的属性名一致, 如果不一致的可以用 as 来补充。 (二) 多参数 public List<XXXBean> getXXXBeanList(String xxId, String xxCode); <select id="getXXXBeanList" resultType="XXBean"> select 字段… from XXX where id=#{0} code = #{1} </select> 由于是多参数那么就不能使用parameterType, 改用#{index}是第几个就用第几个的索引,索引从0开始 (三) Map封装多参数 public List<XXXBean> getXXXBeanList(HashMap map); <select id="getXXXBeanList" parameterType="hashmap" resultType="XXBean"> select 字段… from XXX where id=#{xxId} code = #{xxCode} ...

Created 24246-01-24 · Updated 9096-10-09 · 1 min · 141 words · -

Java JUC Atomic

Java JUC Atomic Java从JDK1.5开始提供了java.util.concurrent.atomic包,方便程序员在多线程环境下,无锁的进行原子操作。原子变量的底层使用了处理器提供的原子指令,但是不同的CPU架构可能提供的原子指令不一样,也有可能需要某种形式的内部锁,所以该方法不能绝对保证线程不被阻塞。 在Atomic包里一共有12个类,四种原子更新方式,分别是原子更新基本类型,原子更新数组,原子更新引用和原子更新字段。Atomic包里的类基本都是使用Unsafe实现的包装类。 基本类: AtomicInteger、AtomicLong、AtomicBoolean; 引用类型: AtomicReference、AtomicReference的ABA实例、AtomicStampedRerence、AtomicMarkableReference; 数组类型: AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray 属性原子修改器 (Updater) : AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater 看到这么多类,你是否觉得很困惑,其实没什么,因为你只需要看懂一个,其余的方法和使用都是大同小异的,相关的类会介绍他们之间的区别在哪里,在使用中需要注意的地方即可。 在使用Atomic系列前,我们需要先知道一个东西就是Unsafe类,全名为: sun.misc.Unsafe,这个类包含了大量的对C代码的操作,包括很多直接内存分配以及原子操作的调用,而它之所以标记为非安全的,是告诉你这个里面大量的方法调用都会存在安全隐患,需要小心使用,否则会导致严重的后果,例如在通过unsafe分配内存的时候,如果自己指定某些区域可能会导致一些类似C++一样的指针越界到其他进程的问题,不过它的具体使用并不是本文的重点,本文重点是Atomic系列的内容大多会基于unsafe类中的以下几个本地方法来操作: public final native boolean compareAndSwapObject(Object obj,long Fieldoffset, Object expect, Object update); public final native boolean compareAndSwapInt(Object paramObject, long paramLong, int paramInt1, int paramInt2); 对象的引用进行对比后交换,交换成功返回true,交换失败返回false,这个交换过程完全是原子的,在CPU上计算完结果后,都会对比内存的结果是否还是原先的值,若不是,则认为不能替换,因为变量是volatile类型所以最终写入的数据会被其他线程看到,所以一个线程修改成功后,其他线程就发现自己修改失败了。 参数1: 被操作的对象 参数2: fieldoffset 被操作的域在对象中的偏移量,其实对比时是对比内存单元,所以需要属性的起始位置,而引用就是修改引用地址 (根据OS、VM位数和参数配置决定宽度一般是4-8个字节) ,int就是修改相关的4个字节,而long就是修改相关的8个字节。 获取偏移量也是通过unsafe的一个方法: objectFieldOffset(Fieldfield)来获取属性在对象中的偏移量;静态变量需要通过: staticFieldOffset(Field field)获取,调用的总方法是: fieldOffset(Fieldfield) 参数3: expect 域的期望值 参数4: update 域的更新值 对long的操作,要看VM是否支持对Long的CAS,因为有可能VM本身不支持,若不支持,此时运算会变成Lock方式,不过现在VM都基本是支持的而已。 public final native boolean compareAndSwapLong(Object paramObject, long paramLong1, long paramLong2, long paramLong3); ...

Created 3036-06-03 · Updated 9096-10-09 · 6 min · 1173 words · -

Java 循环 loop: while, for, foreach

‘java 循环/loop while,for,foreach’ while( 布尔表达式 ) { //循环内容 } do { //代码语句 }while(布尔表达式); JAVA for循环执行顺序 及 i++和++i的区别 1.i与i++的区别是: ++i 是先执行 i=i+1 再使用 i 的值,而 i++ 是先使用 i 的值再执行 i=i+1。 2.但是如果不了解 for 循环的执行顺序则容易出错。 for循环的执行顺序如下: for(sta1;sta2;sta3) { sta4; } 1.进入循环执行sta1;//只是进入的时候执行. 2.执行sta2;//条件为真才执行sta4,不然就跳出for了. 3,执行sta4; 4,执行sta3; 5,再回到第2步开始执行 Java5新特征之foreach语句使用总结 foreach语句是java5的新特征之一,在遍历数组、集合方面,foreach为开发人员提供了极大的方便。 foreach语句是for语句的特殊简化版本,但是foreach语句并不能完全取代for语句,然而,任何的foreach语句都可以改写为for语句版本。 foreach并不是一个关键字,习惯上将这种特殊的for语句格式称之为"foreach"语句。从英文字面意思理解foreach也就是"for 每一个"的意思。实际上也就是这个意思。 foreach的语句格式: for(元素类型t 元素变量x : 遍历对象obj){ 引用了x的java语句; } 下面通过两个例子简单例子看看foreach是如何简化编程的。代码如下: 一、foreach简化数组和集合的遍历 import java.util.Arrays; import java.util.List; import java.util.ArrayList; /** * Created by IntelliJ IDEA. * User: leizhimin * Date: 2007-12-3 * Time: 16:58:24 * Java5新特征之foreach语句使用总结 */ public class TestArray { public static void main(String args[]) { TestArray test = new TestArray(); test.test1(); test.listToArray(); test.testArray3(); } /** * foreach语句输出一维数组 */ public void test1() { //定义并初始化一个数组 int arr[] = {2, 3, 1}; System.out.println("—-1—-排序前的一维数组"); for (int x : arr) { System.out.println(x); //逐个输出数组元素的值 } //对数组排序 Arrays.sort(arr); //利用java新特性for each循环输出数组 System.out.println("—-1—-排序后的一维数组"); for (int x : arr) { System.out.println(x); //逐个输出数组元素的值 } } /** * 集合转换为一维数组 */ public void listToArray() { //创建List并添加元素 List<String> list = new ArrayList<String>(); list.add("1"); list.add("3"); list.add("4"); //利用froeach语句输出集合元素 System.out.println("—-2—-froeach语句输出集合元素"); for (String x : list) { System.out.println(x); } //将ArrayList转换为数组 Object s[] = list.toArray(); //利用froeach语句输出集合元素 System.out.println("—-2—-froeach语句输出集合转换而来的数组元素"); for (Object x : s) { System.out.println(x.toString()); //逐个输出数组元素的值 } } /** * foreach输出二维数组测试 */ public void testArray2() { int arr2[][] = {{4, 3}, {1, 2}}; System.out.println("—-3—-foreach输出二维数组测试"); for (int x[] : arr2) { for (int e : x) { System.out.println(e); //逐个输出数组元素的值 } } } /** * foreach输出三维数组 */ public void testArray3() { int arr[][][] = { {{1, 2}, {3, 4}}, {{5, 6}, {7, 8}} }; System.out.println("—-4—-foreach输出三维数组测试"); for (int[][] a2 : arr) { for (int[] a1 : a2) { for (int x : a1) { System.out.println(x); } } } } } 运行结果: ...

Created 16166-11-16 · Updated 9096-10-09 · 2 min · 389 words · -