Servlet学习——Servlet的线程安全问题

 

目录

1. 什么是线性安全问题

2. JVM中什么数据可能会有线性安全问题

3. Servlet为什么会出现安全问题

4. 线程安全问题举例

5. 解决方案

6. 线程不安全时的作用------统计次数


1. 什么是线性安全问题

同时满足以下两个条件,则会出现线程安全问题。 

  • 存在多线程并发访问
  • 存在可修改的共享数据

当多个线程同时修改同一个共享数据时,后修改的数据会将先修改的数据覆盖,对数据先进行修改的用户读取到的不是自己修改后的数据,这就是线程安全问题

2. JVM中什么数据可能会有线性安全问题

栈内存数据分析 
栈内存是多例的,即 JVM 会为每个线程创建一个栈,所以其中的数据不是共享的。另 外,方法中的局部变量存放在 Stack 的栈帧中,方法执行完毕,栈帧弹栈,局部变量消失。 局部变量是局部的,不是共享的。所以栈内存中的数据不存在线程安全问题。 
堆内存数据分析 
一个 JVM 中只存在一个堆内存,堆内存是共享的。被创建出的对象是存放在堆内存的, 而存放在堆内存中的对象,实际就是对象成员变量的值的集合。即成员变量是存放在堆内存 的。堆内存中的数据是多线程共享的,也就是说,堆内存中的数据是存在线程安全问题的。 
方法区数据分析 
一个 JVM 中只存在一个方法区。静态变量与常量存放在方法区,方法区是多线程共享 的。常量是不能被修改的量,所以常量不存在线程安全问题。静态变量是多线程共享的,所 以静态变量存在线程安全问题

总结:静态变量、成员变量是多线程共享的,可能会出现线性安全问题

3. Servlet为什么会出现安全问题

Servlet 是在单例多线程环境下运行的。其运行可能会出现线程安全问题

 

4. 线程安全问题举例

LoginServlet.java

package com.orbit.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
	//定义成员变量,成员变量是可修改的,故线程不安全
	private String username;	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		username = request.getParameter("uname");
		
		PrintWriter out = response.getWriter();
		out.print("username = " + username);	
	}
}

index.html





Insert title here


	
用户名

使用tomcat的debug模式运行项目:

Servlet学习——Servlet的线程安全问题_第1张图片

Servlet学习——Servlet的线程安全问题_第2张图片

5. 解决方案

对于 Servlet 的使用,一般是不声明成员变量的。若项目中要求必须要声明成员变量,则只能通过线程同步机制 synchronized 避免线程安全问题.

方案①——将成员变量修改为局部变量

LoginServlet.java

package com.orbit.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@WebServlet("/login")
public class LoginServlet extends HttpServlet {
	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		//修改为局部变量
		String username = request.getParameter("uname");
		
		PrintWriter out = response.getWriter();
		out.print("username = " + username);
	}
}

 

使用tomcat的debug模式运行项目:

Servlet学习——Servlet的线程安全问题_第3张图片

Servlet学习——Servlet的线程安全问题_第4张图片

方案②——将对 username 的操作语句均放入同步语句块 synchronized 中,让所有请求进行串行化排队执行

最好不要使用线程同步机制。因为一旦操作进入串行化的排队状态,将大大降低程序的执行效率。 

LoginServlet.java

package com.orbit.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@WebServlet("/login")
public class LoginServlet extends HttpServlet {
	//定义成员变量,成员变量是可修改的,故线程不安全
	private String username;	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		//添加同步锁:缺点为一次只能一个用户通过
		synchronized (this) {
			username = request.getParameter("uname");
			
			PrintWriter out = response.getWriter();
			out.print("username = " + username);
		}			
	}
}

结果与方案①一致(图略)

6. 线程不安全时的作用------统计次数

LoginServlet.java

package com.orbit.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@WebServlet("/login")
public class LoginServlet extends HttpServlet {
	//定义成员变量,成员变量是可修改的,故线程不安全
	private int count;	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		//该servlet每被访问一次,count就加一
		count++;
		response.setContentType("text/html;charset=UTF-8");
		PrintWriter out = response.getWriter();
		out.print("该页面已被访问" + count + "次");
	}
}

Servlet学习——Servlet的线程安全问题_第5张图片

 

 

你可能感兴趣的:(Servlet,线程安全,servlet,Javaweb)