默认情况下,servlet不是在分布式环境中部署的。servlet对声明的每个servlet只创建一个实例。
servlet容器实际上维护了一个线程池来服务成千上百的请求。线程池实际上是一组等待执行代码的线程。这些线程被称为工作者线程。
servlet使用调度者线程来管理工作者线程。
当容器接收到一个servlet的请求的时候。调度者线程从线程池中选取一个工作者线程,然后将请求传递给该线程。由这个线程去执行servlet的service方法。
如果2个线程请求的是同一个servlet,那么该servlet的service方法将会并发的执行。
因此如果为某个servlet定义一个成员变量,那么这个成员变量是不安全的。
正确的方法是将变量设定成成员变量。或是将变量靠threadLocal进行维护。
如果对方法进行同步,那么当成千上万个请求到来时会对方法进行排队。这种效率会非常底下。
如果为servlet定义静态的变量,那么该变量是所有该类的实例中共享的,是不安全的。通常类变量在servlet中常常定义成只读的常量数据。如驱动程序类名,链接URL,密码等等。
错误定义1
将statement定义成类变量然后在各个增、删、该、查方法中使用,这是错误的,因为statement会被多个线程共享类实例,如果一个线程执行完毕后关闭了statement,那么其他的线程执行就会出现错误。
正确的做法是将statement定义到成员变量中去。
实例2,如果将dataSource定义成类变量,当一个线程方法方法时创建了一个connection(从线程池中获取链接)。然后对connection进行关闭(返回线程池中),再没有调用finally将链接引用置2为空时。另一个线程获取链接,正好是刚刚线程返回到链接池中的链接,然后第一个线程判断链接是否为空,若是不为空就关闭链接,这时第二个线程就会出问题。所以解决办法就是关闭链接后要将链接置为空
servlet容器实际上维护了一个线程池来服务成千上百的请求。线程池实际上是一组等待执行代码的线程。这些线程被称为工作者线程。
servlet使用调度者线程来管理工作者线程。
当容器接收到一个servlet的请求的时候。调度者线程从线程池中选取一个工作者线程,然后将请求传递给该线程。由这个线程去执行servlet的service方法。
如果2个线程请求的是同一个servlet,那么该servlet的service方法将会并发的执行。
因此如果为某个servlet定义一个成员变量,那么这个成员变量是不安全的。
正确的方法是将变量设定成成员变量。或是将变量靠threadLocal进行维护。
如果对方法进行同步,那么当成千上万个请求到来时会对方法进行排队。这种效率会非常底下。
如果为servlet定义静态的变量,那么该变量是所有该类的实例中共享的,是不安全的。通常类变量在servlet中常常定义成只读的常量数据。如驱动程序类名,链接URL,密码等等。
错误定义1
将statement定义成类变量然后在各个增、删、该、查方法中使用,这是错误的,因为statement会被多个线程共享类实例,如果一个线程执行完毕后关闭了statement,那么其他的线程执行就会出现错误。
正确的做法是将statement定义到成员变量中去。
实例2,如果将dataSource定义成类变量,当一个线程方法方法时创建了一个connection(从线程池中获取链接)。然后对connection进行关闭(返回线程池中),再没有调用finally将链接引用置2为空时。另一个线程获取链接,正好是刚刚线程返回到链接池中的链接,然后第一个线程判断链接是否为空,若是不为空就关闭链接,这时第二个线程就会出问题。所以解决办法就是关闭链接后要将链接置为空