Servlet 的多线程并发问题:
package com.demo.f_thread;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/*
* Servlet 的多线程并发问题:
* 如果多个线程同时访问了 servlet 对象的共享数据(成员变量),则可能会引发线程安全问题,因为 Servlet 是单实例多线程的。
*/
@WebServlet("/ThreadDemo1")
@SuppressWarnings("serial")
public class ThreadDemo1 extends HttpServlet {
private int count = 1; // 成员变量(共享数据)
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
// 如果线程1执行完输出语句,还没有执行 count++ 语句,
// 线程2就抢到了执行权,执行输出语句,那么线程1和线程2输出的 count 值都是 1.
resp.getWriter().write("你是当前网站的第" + count + "个访客。");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
Servlet 的多线程并发解决办法:
package com.demo.f_thread;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/*
* Servlet 的多线程并发问题:
* 如果多个线程同时访问了 servlet 对象的共享数据(成员变量),则可能会引发线程安全问题,因为 Servlet 是单实例多线程的。
* 解决办法:
* 1、把使用到共享数据(如成员变量)的代码块进行同步(使用 synchronized 关键字进行同步)
* 2、建议在 servlet 类中尽量不要使用成员变量。如果使用了成员变量,必须要同步,而且尽量缩写同步代码块的范围,
* 因为同步会降低多线程并发的效率。(哪里使用了成员变量,就同步哪里!!!)
*/
@WebServlet("/ThreadDemo1")
@SuppressWarnings("serial")
public class ThreadDemo1 extends HttpServlet {
private int count = 1; // 成员变量(共享数据)
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
// 锁对象必须是唯一的,建议使用 类对象。
// 锁中的内容同一时间只允许一个线程执行,其他线程需等待;必须等一个线程执行完了,另一个线程才能执行。
synchronized (ThreadDemo1.class) {
// 没有使用 synchronized 锁的情况下:如果线程1执行完输出语句,还没有执行 count++ 语句,
// 线程2就抢到了执行权,执行输出语句,那么线程1和线程2输出的 count 值都是 1.
resp.getWriter().write("你是当前网站的第" + count + "个访客。");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}