java web 中并发访问的线程安全

前言:最近在学习《Java并发编程实战》 感觉是有一定的难度。正在努力的理解如何编写多线程安全的程序。
发现线程不安全的核心:对共享数据的修改
这就联想到了 Java web ,web 所在的环境就是高并发的,那么如何在高并发的环境下保证自己的web 项目是安全的???

一:web服务器 接收请求时的线程情况

web 服务器处理请求的几种模式:

  1. 收到一个请求就处理,此时不能处理其他的请求,直到这个请求处理完成,这是单线程模型,无法并发,一个请求没处理完服务器就会阻塞,无法处理下一个请求。一般不采用这种方式
  2. 收到一个新的请求就开一个线程去处理,这样的方式看似非阻塞,但是实际上也是阻塞的。相对于1模式来说他是有一定的并发量,但是频繁的开线程也十分的消耗资源
  3. 类似2的模型,但是不是每次收到请求就开一个新的线程,而是使用线程池
    如果不了解线程池,你可能会了解数据库连接池,由于频繁创建、关闭数据库连接会消耗资源,所以会用数据库连接池来保存一定数量的连接,如果需要就从连接池里取连接,不需要则放回连接池,不在频繁创建。线程池也是一样的道理,线程池管理多线程,性能比频繁创建线程高得多。这种方式实现的服务器性能会比2高。不过,它依然是阻塞的。线程池的线程数量通常有限制的,如果所有线程都被阻塞(例如网速慢,或者被人恶意占用连接),那么接下来的请求将会排队等待。
  4. 基于Java NIO实现的服务器模型
    上面说到的几种模型,都是基于BIO(阻塞IO)。而NIO则是非阻塞IO,它是基于IO多路复用技术(例如Reactor模式)实现,只需要一个线程或者少量线程,就可以处理大量请求。从性能上来说NIO实现的服务器并发性一般大于BIO,所以可以实现高性能的服务器。如果感兴趣,可以学习一些基于NIO的网络编程框架,例如Netty、MINA。
    而我们最常见的Tomcat运行可以选择BIO或者NIO模型,原理分别对应上面的3和4两种方式。Tomcat默认是BIO方式运行

二:并发访问的线程安全

既然web 服务器处理请求是并发的,那么是如何保证程序线程安全的???

核心:不声明共享的可变变量

Servlet中的线程安全
Servlet 是单例的,如果在servlet 中声明类变量或者是实例变量,那么该变量就变成了共享资源,当多线程访问该变量的时候就可能存在安全隐患
所以解决的根本就是在servet 中不声明可变类变量或者实例变量
Spring MVC 中的线程安全
在Controller 中不声明:类变量或者实例变量

思考:

一般的程序中充满了并发情况下会出现安全问题的情况,但是你仔细想一想自己写的Java web 项目,就会发现几乎完美的符合不声明类变量和实例变量的情况
比如使用的spring MVC 虽然我们会在Controller 中进行依赖注入,声明了 实例变量,但是这个实例变量中没有任何 的可变状态,在Service 中没有任何的类变量和实例变量,这个实例引用只是起调用方法的作用,而在Controller,Service 中所有的业务逻辑处理都在方法中,不存在线程之间的共享,而线程唯一贡献的数据就是数据库,而数据本身自己是可以进行并发访问的。
所以在Java web 中多西安城是安全的,并且开发的环境是单线程的,但是又并不影响整个程序在多线程情况下的安全性。


学习的必要性的思考:
虽然做的事Java web 的后端开发,看起来使用任何一种情况好像都是线程安全的那么为什么要学习多线程,理解如何编写多线程安全的程序,我们所使用的框架都是经过了层层的封装,但是在底层,就算是一个Java API 中的方法他是对自己的线程安全性做了要求的,所谓你看看得见多久的以前,你就看得见多远的未来。

你可能感兴趣的:(java web 中并发访问的线程安全)