Tomcat中的ApplicationFilterChain如何保证其成员变量(例如pos和n)的线程安全?

Tomcat中的ApplicationFilterChain是针对每个Url Pattern的单例,它如何保证其成员变量(例如pos和n)的线程安全?
贴上源码:

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.catalina.core;

import java.io.IOException;
import java.security.Principal;
import java.security.PrivilegedActionException;
import java.util.Set;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.Globals;
import org.apache.catalina.security.SecurityUtil;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.res.StringManager;

/**
 * Implementation of <code>javax.servlet.FilterChain</code> used to manage
 * the execution of a set of filters for a particular request.  When the
 * set of defined filters has all been executed, the next call to
 * <code>doFilter()</code> will execute the servlet's <code>service()</code>
 * method itself.
 *
 * @author Craig R. McClanahan
 */
public final class ApplicationFilterChain implements FilterChain {

    // Used to enforce requirements of SRV.8.2 / SRV.14.2.5.1
    private static final ThreadLocal<ServletRequest> lastServicedRequest;
    private static final ThreadLocal<ServletResponse> lastServicedResponse;

    static {
        if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
            lastServicedRequest = new ThreadLocal<>();
            lastServicedResponse = new ThreadLocal<>();
        } else {
            lastServicedRequest = null;
            lastServicedResponse = null;
        }
    }

    // -------------------------------------------------------------- Constants


    public static final int INCREMENT = 10;


    // ----------------------------------------------------- Instance Variables

    /**
     * Filters.
     */
    private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];


    /**
     * The int which is used to maintain the current position
     * in the filter chain.
     */
    private int pos = 0;


    /**
     * The int which gives the current number of filters in the chain.
     */
    private int n = 0;


    /**
     * The servlet instance to be executed by this chain.
     */
    private Servlet servlet = null;


    /**
     * Does the associated servlet instance support async processing?
     */
    private boolean servletSupportsAsync = false;

    /**
     * The string manager for our package.
     */
    private static final StringManager sm =
      StringManager.getManager(Constants.Package);


    /**
     * Static class array used when the SecurityManager is turned on and
     * <code>doFilter</code> is invoked.
     */
    private static final Class<?>[] classType = new Class[]{
        ServletRequest.class, ServletResponse.class, FilterChain.class};

    /**
     * Static class array used when the SecurityManager is turned on and
     * <code>service</code> is invoked.
     */
    private static final Class<?>[] classTypeUsedInService = new Class[]{
        ServletRequest.class, ServletResponse.class};


    // ---------------------------------------------------- FilterChain Methods

    /**
     * Invoke the next filter in this chain, passing the specified request
     * and response.  If there are no more filters in this chain, invoke
     * the <code>service()</code> method of the servlet itself.
     *
     * @param request The servlet request we are processing
     * @param response The servlet response we are creating
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a servlet exception occurs
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response)
        throws IOException, ServletException {

        if( Globals.IS_SECURITY_ENABLED ) {
            final ServletRequest req = request;
            final ServletResponse res = response;
            try {
                java.security.AccessController.doPrivileged(
                    new java.security.PrivilegedExceptionAction<Void>() {
                        @Override
                        public Void run()
                            throws ServletException, IOException {
                            internalDoFilter(req,res);
                            return null;
                        }
                    }
                );
            } catch( PrivilegedActionException pe) {
                Exception e = pe.getException();
                if (e instanceof ServletException)
                    throw (ServletException) e;
                else if (e instanceof IOException)
                    throw (IOException) e;
                else if (e instanceof RuntimeException)
                    throw (RuntimeException) e;
                else
                    throw new ServletException(e.getMessage(), e);
            }
        } else {
            internalDoFilter(request,response);
        }
    }

    private void internalDoFilter(ServletRequest request,
                                  ServletResponse response)
        throws IOException, ServletException {

        // Call the next filter if there is one
        if (pos < n) {
            ApplicationFilterConfig filterConfig = filters[pos++];
            try {
                Filter filter = filterConfig.getFilter();

                if (request.isAsyncSupported() && "false".equalsIgnoreCase(
                        filterConfig.getFilterDef().getAsyncSupported())) {
                    request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
                }
                if( Globals.IS_SECURITY_ENABLED ) {
                    final ServletRequest req = request;
                    final ServletResponse res = response;
                    Principal principal =
                        ((HttpServletRequest) req).getUserPrincipal();

                    Object[] args = new Object[]{req, res, this};
                    SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
                } else {
                    filter.doFilter(request, response, this);
                }
            } catch (IOException | ServletException | RuntimeException e) {
                throw e;
            } catch (Throwable e) {
                e = ExceptionUtils.unwrapInvocationTargetException(e);
                ExceptionUtils.handleThrowable(e);
                throw new ServletException(sm.getString("filterChain.filter"), e);
            }
            return;
        }

        // We fell off the end of the chain -- call the servlet instance
        try {
            if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
                lastServicedRequest.set(request);
                lastServicedResponse.set(response);
            }

            if (request.isAsyncSupported() && !servletSupportsAsync) {
                request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
                        Boolean.FALSE);
            }
            // Use potentially wrapped request from this point
            if ((request instanceof HttpServletRequest) &&
                    (response instanceof HttpServletResponse) &&
                    Globals.IS_SECURITY_ENABLED ) {
                final ServletRequest req = request;
                final ServletResponse res = response;
                Principal principal =
                    ((HttpServletRequest) req).getUserPrincipal();
                Object[] args = new Object[]{req, res};
                SecurityUtil.doAsPrivilege("service",
                                           servlet,
                                           classTypeUsedInService,
                                           args,
                                           principal);
            } else {
                servlet.service(request, response);
            }
        } catch (IOException | ServletException | RuntimeException e) {
            throw e;
        } catch (Throwable e) {
            e = ExceptionUtils.unwrapInvocationTargetException(e);
            ExceptionUtils.handleThrowable(e);
            throw new ServletException(sm.getString("filterChain.servlet"), e);
        } finally {
            if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
                lastServicedRequest.set(null);
                lastServicedResponse.set(null);
            }
        }
    }


    /**
     * The last request passed to a servlet for servicing from the current
     * thread.
     *
     * @return The last request to be serviced.
     */
    public static ServletRequest getLastServicedRequest() {
        return lastServicedRequest.get();
    }


    /**
     * The last response passed to a servlet for servicing from the current
     * thread.
     *
     * @return The last response to be serviced.
     */
    public static ServletResponse getLastServicedResponse() {
        return lastServicedResponse.get();
    }


    // -------------------------------------------------------- Package Methods

    /**
     * Add a filter to the set of filters that will be executed in this chain.
     *
     * @param filterConfig The FilterConfig for the servlet to be executed
     */
    void addFilter(ApplicationFilterConfig filterConfig) {

        // Prevent the same filter being added multiple times
        for(ApplicationFilterConfig filter:filters)
            if(filter==filterConfig)
                return;

        if (n == filters.length) {
            ApplicationFilterConfig[] newFilters =
                new ApplicationFilterConfig[n + INCREMENT];
            System.arraycopy(filters, 0, newFilters, 0, n);
            filters = newFilters;
        }
        filters[n++] = filterConfig;

    }


    /**
     * Release references to the filters and wrapper executed by this chain.
     */
    void release() {
        for (int i = 0; i < n; i++) {
            filters[i] = null;
        }
        n = 0;
        pos = 0;
        servlet = null;
        servletSupportsAsync = false;
    }


    /**
     * Prepare for reuse of the filters and wrapper executed by this chain.
     */
    void reuse() {
        pos = 0;
    }


    /**
     * Set the servlet that will be executed at the end of this chain.
     *
     * @param servlet The Wrapper for the servlet to be executed
     */
    void setServlet(Servlet servlet) {
        this.servlet = servlet;
    }


    void setServletSupportsAsync(boolean servletSupportsAsync) {
        this.servletSupportsAsync = servletSupportsAsync;
    }


    /**
     * Identifies the Filters, if any, in this FilterChain that do not support
     * async.
     *
     * @param result The Set to which the fully qualified class names of each
     *               Filter in this FilterChain that does not support async will
     *               be added
     */
    public void findNonAsyncFilters(Set<String> result) {
        for (int i = 0; i < n ; i++) {
            ApplicationFilterConfig filter = filters[i];
            if ("false".equalsIgnoreCase(filter.getFilterDef().getAsyncSupported())) {
                result.add(filter.getFilterClass());
            }
        }
    }
}

0

1个回答

0
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
其他相关推荐
tomcat 责任链设计模式 底层源码剖析
今天晚上花了些时间debug了下tomcat,注意观察了下tomcat内部过滤器的实现,其实tomcat内部过滤器采用了责任链的设计模式, (其实struts2拦截器那一块采用了相似的设计模式),以下是个人对源码的解读, ApplicationFilterChain详解 首先是对该类的定义的介绍/** * Implementation of &amp;lt;code&amp;gt;javax.servlet...
类的实例中的私有成员是否线程安全--实例
// 本程序用来说明 类的实例中的私有成员是否线程安全 public class Zy_thread_test1  {     public static void main(String[] args)      {         hello  tHello=new hello(); //这里创建一个对象                     for(int j=0;j&amp;lt;5;...
成员变量与局部变量与sychronized和效率与线程安全的关系
从JVM内存的层面来讲,线程不安全是因为多线程共用堆内存引起的,多线程是为了提高程序运行效率而来的,因为成员变量在堆内存中,而局部变量是随栈的所以不会影响线程安全,另外可以通过sychronized(){}修饰代码或方法达到对共用数据的保护。这样我们就有了三种模式,三种模式各有利弊。 1,使用成员变量 优点节约了栈消耗的内存,总体节约了内存 缺点是多线程下会造成线程不安全 2,使用
Java中变量的线程安全问题
[b]静态变量:线程非安全。 [/b] 静态变量即类变量,位于方法区,为所有对象共享,共享一份内存,一旦静态变量被修改,其他对象均对修改可见,故线程非安全。 [b]实例变量:单例模式(只有一个对象实例存在)线程非安全,非单例线程安全。[/b] 实例变量为对象实例私有,在虚拟机的堆中分配,若在系统中只存在一个此对象的实例,在多线程环境下,“犹如”静态变量那样,被某个线程修改后,其他线...
java 测试单例中的成员方法是否线程安全
这个是作为单例的类:public class SingleClass { public String myName = "zero";// 单例的名字,可以通过修改该成员变量,判断单例是否真的只有一个,本例子没做这部分内容判断,感兴趣可以自己改一下这个名字后,输出一下 private static SingleClass self;// 持有自身对象的引用 private Sing
JAVA 多线程对成员变量与局部变量的影响
1 http://www.cnblogs.com/eason-chan/p/3684194.html
Java面试题:Servlet是线程安全的吗?
Servlet不是线程安全的。要解释为什么Servlet为什么不是线程安全的,需要了解Servlet容器(即Tomcat)使如何响应HTTP请求的。当Tomcat接收到Client的HTTP请求时,Tomcat从线程池中取出一个线程,之后找到该请求对应的Servlet对象并进行初始化,之后调用service()方法。要注意的是每一个Servlet对象再Tomcat容器中只有一个实例对象,即是单例模...
springMVC 默认单例 那些变量是线程安全的
springMVC负责的controller层的类默认是单例模式的,单例模式少去了重复创建对象,垃圾内存回收的过程,在性能方面有一些提升。但是,http请求往往是同时多个请求进来的,这样就会开启多个线程来运行controller,那controller在单例模式下,类中定义的属性那些是线程安全的呢?那些是线程不安全的呢?做了以下几个测试:package com.lee.controller; i...
属性和变量的线程安全问题
线程安全的只有:请求作用域属性和服务方法中的局部变量, 其他的如:上下文作用域属性、会话作用域属性、servlet中的实例变量以及servlet中的静态变量都是不安全的,都可能由多个线程处理,除非采取特别的防范措施。 对于处理servlet和线程安全问题,推荐完全使用局部变量,如果必须使用实例变量,则同步对实例变量的访问。保护上下文属性,需要对上下文加锁:public void doPost(H
spring的DispatcherServlet不是线程安全的.
大概看了一下tomcat实例化servlet的源代码,和spring mvc的DispatcherServlet的源代码,现在问题来了,spring的DispatcherServlet不是线程安全的. 我看的源代码版本是:tomcat 7.0.57 spring 3.0.5. 重点查看了org.apache.catalina.core.StandardWrapper和DispatcherSe...
tomcat源码解析(四)--请求过程之路径的匹配
好了接着上篇分析,tomcat分析完请求头之后,是怎么把请求发送给对应的servlet的呢? 看到org.apache.coyote.http11.Http11Processor类的service方法中,有这么一句: getAdapter().service(request, response); 这里的request会把浏览器的发过来的信息,解析之后放在这里. 跟进,service方法,
spring 线程安全问题
一直有个疑惑,spring是怎么处理自己的线程安全问题的呢,这里简单说明下。 1、介绍两个概念 有状态的bean:对象中有实例变量(成员变量),可以保存数据,是非线程安全的。 无状态的bean:对象中没有实例变量(成员变量),不能保存数据,可以在多线程环境下共享,是线程安全的。 2、spring的线程安全问题 2.1 我们都知道spring中的bean默认都是单例的,ioc容器中一个类只...
成员变量和局部变量在多线程中使用的区别
public class ThreadTest implements Runnable { public static void main(String[] args) { //只创建了一个对象 Runnable r = new ThreadTest(); //该对象创建了两个线程 Thread t1 = new Thread(r); Thread t2 = new Th...
线程分别改变不同成员变量是线程安全的
启用三个线程, 对同一个对象中的三个不同成员变量操作, 是线程安全的 zdxy-data-report中的一段代码 status.set(3); try { threadPoolTaskExecutor.execute(new Innerthread1(paperId, clazzId, clazzScoreResult, personalScoreAdapter)); } ca
Java多线程6:实例变量非线程安全
如果多个线程共同访问1个对象中的实例变量,则有可能出现“非线程安全”问题。 成员变量的初始化和内存中的运行机制 接下来以下面代码来举例说明成员变量的初始化和内存中的运行机制 public class Person { public static int num; public String name; public static void main(String[...
springMVC 谨慎使用成员变量
1.springMVC默认是单例的 对于同一个Controller,只会生成一个实例来处理所有的请求,因此bean实例只会实例化一次,并被存放在工厂中,以供其他请求使用。 在不定义成员变量的情况下是线程安全的。 单例的优点:    1)每次请求不需要重新new一个对象。    2)垃圾收集和回收时更有效率。 Struts2是类级别的,需要原型实现; SpringMVC是方法级的,
2017.2.22 多线程访问成员变量造成的问题及改正
多线程访问成员变量造成的问题及改正 参考资料: http://blog.csdn.net/gaogaoshan/article/details/23910355 http://blog.csdn.net/gaogaoshan/article/details/9312703   1 项目中的问题 项目中出现了一个问题,当多个线程访问时,AuthPermissionResolver出现了多
Spring MVC Controller线程安全性问题
Spring MVC默认是单例模式,Controller、Service、Dao都是单例所以在使用不当存在一定的安全隐患。Controller单例模式的好处在与: 1. 提高性能,不用每次创建Controller实例,减少了对象创建和垃圾收集的时间 2. 根本就不需要多例 由于只有一个Controller的实例,当多个线程同时调用它的时候,它的成员变量就不是线程安全的。 当然在大多
过滤器、监听器、上下文、servlet线程安全问题
就像名字写那样,过滤器可以过滤请求,比如对一些评论进行过滤。又不改原有代码的基础上可以加上一个过滤器,或者是登陆验证。集中在一个过滤器中处理。写一个类实现接口 Filter 之后一定要在配置文件中配置!!!监听器可以监听,上下文的概念。过滤器:什么是过滤器: servlet规范当中定义的一种特殊的组件,用来拦截servlet容器的调用过程。 会先调过过滤器的方法,过滤器决定是否向后继续调用就是调
response线程安全详解
方法注入 本地保存 实例字段注入 response实现类 结论 获取response 本文主要分析 HttpServletResponse 注入的线程安全问题 问 HttpServletResponse 是不是线程安全? 这个答案要针对具体的场景才能说明,接下来用3个场景演示 HttpServletResponse 是不是线程安全这个疑问 方法注入 先来看一段例子: ...
全局变量的线程安全性
类的全局变量包含三种:值不会变的常量;单例模式的变量;多例模式的变量 常量和多例模式的变量永远是线程安全的 单例模式的变量就需要仔细考虑一下了: 如果单例模式的变量只是一个service,用它只是调用它的方法,不管方法是否有参数, 都是线程安全的 如果单例模式的变量虽是一个service,但调用者会给该service的一些属性赋值,并且这些值会在方法调用的时候发生作用,那么这个servic
servlet与Struts action线程安全问题分析
servlet与Struts action线程安全问题分析
python练习题(一)
first week 字符串拼接 用户输入两个字符串,将它们组合后输出 str1 = input("Wanghui") str2 = input("Los Angeles") print("世界这么多,{}想去{}看看。".format(str1,str2)) 整数序列求和 用户输入一个正整数 N,计算从 1 到 N(包含 1和 N)相加之后的结果 n = input("please input
如何证明Java多线程中的成员变量数据是互不可见的
前面的几篇文章主要介绍了Java的内存模型,进程和线程的定义,特点和联系,其中在Java多线程里面有一个数据不可见的问题而我们知道使用volatile可以解决,但是如何证明这个多线程修改共享数据是不可见的呢? 很简单,看下面的一段代码: [code=&quot;java&quot;]````java private static boolean keepRunning=true; ...
设计模式之责任链模式(tomcat filters)
责任链模式是指由某件任务可以由很多处理者处理,这些处理者保存着下一个处理者的引用,行程一条链,每个处理者只能处理该任务或者将任务交由下一个处理者处理,直到该任务被某个处理者处理或者最终没有处理者为止,该任务由最开始并不知道是谁来处理这个任务,只是把任务抛给第一个处理者而已。   责任链模式类图:   个人觉得也可以不用把一个handler注入另一个handler,虽然与原始的责任链模式...
ThreadLocal-单例模式下高并发线程安全
为了解决线程安全的问题,我们有3个思路: 第一每个线程独享自己的操作对象,也就是多例,多例势必会带来堆内存占用、频繁GC、对象初始化性能开销等待等一些列问题。 第二单例模式枷锁,典型的案例是HashTable和HashMap,对读取和变更的操作用synchronized限制起来,保证同一时间只有一个线程可以操作该对象。虽然解决了内存、回收、构造、初始化等问题,但是势必会因为锁竞争带来高并发下性能的下降。 第三个思路就是今天重点推出的ThreadLocal。单例模式下通过某种机制维护成员变量不同线程的版本。
java中final与volatile-线程安全问题
在线程安全问题中final主要体现在安全发布问题上,在这里先讲一下什么事安全发布,在《java并发编程实践》一书中有讲,不过看起来挺难懂的…. public class Holder { private int n; public Holder(int n) { this.n = n; } public void assertSanity() {
如何保证线程安全 实现线程安全有那些方法
1,如何保证线程安全 不在线程之间共享状态变量 将状态变量修改成不可变的变量 在访问状态变量时使用同步   2,实现线程安全有那些方法 A:内置锁 public class widget{ public synchronized void doSomething(){ ..... } } public class Loggi...
spring中bean的线程安全问题
Spring容器生成的Bean都是默认单例的,那么spring是怎么处理并发的情况下线程安全问题呢? 在讲单例和线程安全之前首先我们要明白一点,那就是在单例模式下多线程也可以同时访问同一个对象。单例模式顾名思义,所有的线程来调用方法的时候都是由同一个实例对象来调用方法的,那么如果设计一个类的实现为单例,当多个线程调用方法时会不会出现线程安全问题呢?答案是不会,为什么呢,其实很简单,我们可以从线程...
i++和++i是否是线程安全的?
首先从两方面考虑:是单例还是多例 多例:对于任何变量,对象都是安全的 单例(从成员变量和局部变量考虑) ① 成员变量(从是常量还是变量考虑)成员变量是同一进程中其他线程都可以访问到的。 常量----是线程安全的 变量----是线程不安全的 ② 局部变量,是线程安全的,因为局部变量线程是私有的,其他线程是访问不到的。 ...
SpringBoot 单例Bean中实例变量线程安全研究
文章目录一.单例模式有全局变量存在的问题二.采用原型模式实现多例三.采用ThreadLocal 将变量绑定在线程上 &nbsp;成员变量、全局变量、实例变量、类变量、静态变量和局部变量的区别 &nbsp;&nbsp;Spring框架里的bean,或者说组件,获取实例的时候都是默认的单例模式,这是在多线程开发的时候要尤其注意的地方。 &nbsp;&nbsp;单例模式的意思就是只有一个实例。单例模式确...
线程安全、线程私有变量
线程安全:无论有多少个线程调用这个函数,此函数都会给相应的线程返回正确的结果。 看下面这个例子: 很明显我们在rebuf这个函数里返回了一个局部变量,在rebuf这个函数运行完之后,局部变量就会被销毁,所以我们打印出来的是这个样子的。 那我们改进呢,函数运行完之后,局部变量就会被销毁,那我们就不让它销毁,加上static关键字
浅谈android的线程安全和handler处理
android的UI操作不是安全的,同时也只有主线程才能操作UI,同时主线程对UI操作有一定的时间限制(最长5秒)。为了能够作一些比较好使的操作(比如下载、打开大文件等),android提供了一些列机制。线程安全:如果你的代码所在的进程中又多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也喝预期的是一样的,就是线程安全的,或者说:一
C3P0 在tomcat中如何配置
C3P0 在tomcat中如何配置C3P0 在tomcat中如何配置C3P0 在tomcat中如何配置C3P0 在tomcat中如何配置
java中线程安全问题如何解决?
线程安全问题解决方法: 在代码中使用同步代码块(同步锁) 解释:在某一段任务中,同一时间只允许一个线程执行任务,其他的线程即使抢到了cpu,也无法进入当前的任务区间,只有当 当前的线程将任务执行完后,其他的线程才有资格进入. 同步代码块的构成: synchronized(锁(对象)){      同步的代码 } 作为锁对象的要求: 1.必须是对象 2.必须保证被多线程共享 可...
关于对static修饰的成员变量理解
第一步:建立Controller (用的SSM) @Controller @RequestMapping(&quot;xc&quot;) public class TestController{ @RequestMapping(value=&quot;/testPri&quot;) @ResponseBody public String Test(){ new TestPriv().testPri(); return ...
高并发下的线程安全实现——线程局部变量
今天我们来讨论另外一种线程安全的实现方法。如果说互斥同步是多线程间的数据共享,那么线程局部变量就是线程间的数据隔离。ThreadLocal把共享数据的可见范围限制在同一个线程之内,这样无须同步也能实现线程之间数据不争用的问题。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本
Filter的线程安全问题
6)Filter的线程安全问题:马 克-to-win:和Servlet一样,为了提高性能,Filter也采取多线程模式。即:每一个线程来应答一个用户浏览器,而且这个线程和用户要访问 的目标Servlet的线程是同一个线程。说得更准确一点,当用户访问某个资源需要经过过滤器时,服务器中一个线程为了应答这个客户请求,先调用过滤器中 的doFilter方法,再根据是否有chain.doFilter的指令,...
Tomcat与多线程
1、症状: LZ正在做一个网络爬虫,发现一次加载5000个url,开10个thread,会造成堆内存占用持续走高,垃圾回收后期不太明显,如右上角图示。 2、Tomcat优化参数如下: set CATALINA_OPTS=" -server -Xms1024M -Xmx2048M -Xss512k -XX:NewSize=512M -XX:MaxNewSize=512M -XX:PermSize
VB 使用POS机.txt
VB 使用POS机,VB中如何与POS机关联,实现POS机打印
相关热词 c#串口测试应用程序 c# 匹配 正则表达式 c#防止窗体重绘 c#读写txt文件 c#挖地雷源代码 c#弹框选项 c# 移除 队列 c# 密码写入配置文件 c# 获取可用内存大小 c# 嵌入excel编辑