今天看到一篇文章,上面这样提到:
“在Struts的生命周期中,只会为每个Action类创建一个实例,所有的客户请求共享这个实例。因此,必须保证在多线程环境中,Action也能正常工作。因此在Action类中要谨慎使用实例变量...
如果在Action类中定义了实例变量,那么在Action实例的整个生命周期中,这个实例变量被所有请求的线程共享。因此不能在Action类,特别是execute方法中定义代表特定客户状态的实例变量。如果要采用实例变量,需要采用Java的线程同步机制..”
我有点不太明白:
通常一个ActionForm对象作为Action类中execute()方法的参数传入。并且我们可能会调用相应的get,set方法来对这个ActionForm对象中存储的用户提交的表单中信息进行操作。甚至将这个ActionForm对象转发给其他处理业务逻辑的java类。 如果按照上面文章中提到的在Action实例中定义的实例变量会被所有调用Action实例的线程所共享。那么通常有n个不同的用户因为同时递交相同的表单而使用这个Action实例(将各自request/session内的ActionForm实例作为参数传递给这个Action的实例),会不会相互间产生影响呢?这里java虚拟机是怎样处理各自传递来的对象的呢?
请哪位大侠能帮我指点一下,非常非常地感谢您!
还有这句不懂:
"因此不能在Action类,特别是execute方法中定义代表特定客户状态的实例变量。
如果要采用实例变量,需要采用Java的线程同步机制.."
不是说在方法中定义的变量是线程安全的吗,为什么在execute方法中定义表示客户状态的实例变量还要同步啊?什么是代表特定客户状态的实例变量呢?
能将我问的问题解决,我定把分跟您!
未能全部解决的,给部份分,呵呵!先谢了!
“在Struts的生命周期中,只会为每个Action类创建一个实例,所有的客户请求共享这个实例。因此,必须保证在多线程环境中,Action也能正常工作。因此在Action类中要谨慎使用实例变量...
如果在Action类中定义了实例变量,那么在Action实例的整个生命周期中,这个实例变量被所有请求的线程共享。因此不能在Action类,特别是execute方法中定义代表特定客户状态的实例变量。如果要采用实例变量,需要采用Java的线程同步机制..”
我有点不太明白:
通常一个ActionForm对象作为Action类中execute()方法的参数传入。并且我们可能会调用相应的get,set方法来对这个ActionForm对象中存储的用户提交的表单中信息进行操作。甚至将这个ActionForm对象转发给其他处理业务逻辑的java类。 如果按照上面文章中提到的在Action实例中定义的实例变量会被所有调用Action实例的线程所共享。那么通常有n个不同的用户因为同时递交相同的表单而使用这个Action实例(将各自request/session内的ActionForm实例作为参数传递给这个Action的实例),会不会相互间产生影响呢?这里java虚拟机是怎样处理各自传递来的对象的呢?
请哪位大侠能帮我指点一下,非常非常地感谢您!
还有这句不懂:
"因此不能在Action类,特别是execute方法中定义代表特定客户状态的实例变量。
如果要采用实例变量,需要采用Java的线程同步机制.."
不是说在方法中定义的变量是线程安全的吗,为什么在execute方法中定义表示客户状态的实例变量还要同步啊?什么是代表特定客户状态的实例变量呢?
能将我问的问题解决,我定把分跟您!
未能全部解决的,给部份分,呵呵!先谢了!
解决方案 »
- 判断URL是否有效,找了几天,有没有谁能给一个真正能用的
- 一定都要看看哦!
- 想实现JS弹出层,没有玩转,怎么回事?
- 在java中如何读到weblogic 的hostname(不是IP)和username?
- apache fileupload 组件问题 在线等 急!!!
- org.hibernate.mappingException:unknown entity
- 如何控制卖给人家的web程序的连接数? 不用session
- 急!!! 提示:java.sql.SQLException: [Microsoft][ODBC 驱动程序管理器] 无效的游标状态
- 在B/S系统中打印问题 ——在线等,马上结账。
- 怪问题,高手进来看看
- jsp登录问题
- 请问怎样jsp页面中调用一个java类?
因为实例变量是被多线程共享的,所以是不安全的.
举例如下:
package net.oicp.sunflowerbbs;
import java.io.*;
import java.sql.*;
import java.util.*;import javax.servlet.*;
import javax.servlet.http.*;public class SomeServlet extends HttpServlet
{
private Connection con;
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException,Exception{
try
{
Class.forName("someDriver");
con=DriverManager.getConnection("url","user","password");
//下面是一系列数据库操作....
//...
}
catch(Exception e)
{
e.printStackTrace();
}
}
}考虑当两个请求同时到达,只差隔几百毫秒.这时会发生什么,第一个请求打开数据库连接,保存其引用至con实例变量,然后他执行一个数据库操作.同时第二个请求到达,打开另一连接,在同一con实例变量中保存其引用.如果第一个操作完成,试图做另一个数据库操作,其不再拥有初始连接对象---他只知道第二个,然后试图使用第2个连接时就会发生错误. 实例变量的安全性就在于,没有任何方式可以确保另一线程内的请求由于将其自身的引用保存到变量中而不打断该变量的连续性. 解决此问题,可以:
在服务方法中定义局部变量.
如果在action类中定义了实例变量,那么在整个action实例的生命周期中,这个实例变量是被所有请求线程共享.看清楚
上面这句话问题多多: 在execute定义的变量只能叫局部变量.
局部变量不会被线程共享,肯定是安全的
package com.yumeng.sshdemo.action;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;import com.yumeng.sshdemo.form.EmployeeForm;
import com.yumeng.sshdemo.po.Employee;
import com.yumeng.sshdemo.service.EmployeeServices;
public class DeleteAction extends Action {
private EmployeeServices employeeServices;
public EmployeeServices getEmployeeServices() {
return employeeServices;
}
public void setEmployeeServices(EmployeeServices employeeServices) {
this.employeeServices = employeeServices;
}
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
EmployeeForm employeeForm = (EmployeeForm) form;
Employee employee = new Employee();
employee.setEmployee_id(employeeForm.getemployee_id());
employeeServices.deleteEmployee(employee);
return mapping.findForward("delete");
}
}
在这里我定义了一个类级变量,这段程序会有线程安全问题吗?EmployeeServices在Spring配置文件中被配置为singleton=false,在并发访问的时候会出现混乱吗?
这个的意思是说下面这种:
public class XXXAction extends Action {
private String userName; public ActionForward execute(...) {
userName = request.getParameter(...);
functionA();
}
private functionA() {
xxx(userName);
}
}这个例子里,userName就是出问题的“实例变量”,由于Action只创建一个实例,那么多线程环境下,线程1运行到functionA()的时候,线程2可能就把userName给改掉了,所以导致线程1的运行结果出错。别笑哦,我真见过这么写的.....至于你给出的代码,类似DAO的模式,一般来说,即使是singleton=true,也不会有问题的(一般也应该用singleton)。
而"因此不能在Action类,特别是execute方法中定义代表特定客户状态的实例变量。
如果要采用实例变量,需要采用Java的线程同步机制.." 这句话我个人认为很值得推敲,建议楼主别再去花精力琢磨它了
像你这样"删掉get set 后面改成(new EmployeeServices()).deleteEmployee(employee);"还要SPRING干什么呢.还哪来的IOC