当前位置:天才代写 > tutorial > JAVA 教程 > Java中finalize()的另类用法

Java中finalize()的另类用法

2017-11-11 08:00 星期六 所属: JAVA 教程 浏览:301

副标题#e#

做过JAVA编程的都知道,在JAVA中有一种垃圾收集器的机制,当它运行时(凡是在系统内存低到必然限度时自动运行),会接纳不再利用的工具所占用的内存,所以,在JAVA措施中,我们凡是只思量建设工具,而从不体贴工具的排除。Finalize()是JAVA为类提供的一种非凡要领。垃圾收集器的事情进程大抵是这样的:一旦垃圾收集器筹备好释放无用工具占用的存储空间,它首先挪用那些工具的finalize()要领,然后才真正接纳工具的内存。通过利用finalize(),就可以在垃圾收集器运行期间举办一些非凡的事情。下面一例就说明白finalize()的一种巧妙用法。

此刻的贸易应用系统越来越多的回收WEB形式。在WEB形式应用中,每一次页面会见是独立的,前后不相关联,哪怕多个用户在同一时刻会见应用的同一个页面,用户彼此之间也是不知道的。假如想要查抄当前有哪些用户正在利用系统(如筹备规复数据备份或举办系统进级时,系统打点员都很但愿知道这些信息),该怎么办呢? 基于Servlet、Jsp技能的WEB处事器提供了隐含的Session、Application工具,操作它可以帮开拓者实现一些信息的一连生存和共享。当用户会见一个WEB应用时,WEB处事器会自动建设一个Session工具,该工具可以供用户在会话期内涵应用的所有页面中共享数据; Application是WEB应用的一个全局工具。操作Session、Application工具,可以到达跟踪所有用户信息的目标。

当用户打开欣赏器开始请求WEB应用的登录页面时,WEB处事即为该客户建设一个session,从此,在session的timeout时间内,该客户都利用这个session(timeout时间可配置,如Tomcat处事器是在各应用的web.xml文件中配置)。假如利用IE欣赏器,Session与客户IP地点、客户措施历程ID所配合标识的毗连有对应干系,沟通IP地点、沟通历程的窗口(如通过IE-文件-新建-窗口 打开的新窗口)具有同一个session,所以session可用于标识各个独立的客户应用毗连。

下面是一个样例

为了利便处理惩罚,先建一个简朴类(user)用来表达用户信息及存放sessionId:

package com;
public class user {
public String name="";
public String sessionId="";
}

另一个类(testSession)用于处理惩罚用户的login、logout等行动信息,使系统可以跟踪当前毗连的用户信息。

package com;
import java.util.Vector;
import com.user;
public class testSession {
public user User;
private Vector vsid;
public testSession()
{
User=new user();
}
public boolean verify(String username,String password)
throws Exception //验证用户/暗码
{
return true;
}
public void setSessionVar(String sesid,Vector sid) {
this.User.sessionId=sesid;
this.vsid=sid;
}
private static synchronized void addappses(user puser,
Vector pvsid) { //记录一个新毗连的用户
int pos=-1;
user l_user;
if (puser==null || pvsid==null)
return;
for(int i=0;i<pvsid.size();i++){
l_user=(user)pvsid.get(i);
if(l_user.sessionId.equals(puser.sessionId)){
pos=i;
break;
}
}
if(pos==-1){
pvsid.add(puser);
}
else{
pvsid.set(pos,puser);
}
}
private static synchronized void removeappses(user puser,
Vector pvsid) { //移除一个退出的用户
int pos=-1;
user l_user;
if (puser==null || pvsid==null)
return;
for(int i=0;i<pvsid.size();i++){
l_user=(user)pvsid.get(i);
if(l_user.sessionId.equals(puser.sessionId)){
pos=i;
break;
}
}
if(pos!=-1){
pvsid.remove(pos);
}
}
protected void finalize() {
this.removeappses(this.User,this.vsid);
}
public boolean login(String username) throws Exception
{ //处理惩罚登录
this.User.name=username;
this.addappses(this.User,this.vsid);
return true;
}
public boolean logout() throws Exception
{ //处理惩罚注销
this. finalize();
this.User=null;
this.vsid=null;
return true;
}
}


#p#副标题#e#

每一个用户均成立一个testSession工具,来生存该用户的信息。为了对类testSession举办说明,必需同时引人另一个文件logintest.jsp。这个用于示例的JSP文件提供一个简朴的界面举办登录、注销处理惩罚。文件内容如下:

<%@ page import=" com.testSession,
java.util.Vector"%>
<%@page contentType="text/html;charset=GBK" %>
<% request.setCharacterEncoding(response.
getCharacterEncoding());%>
<%
String actionType=request.getParameter("actiontype");
String actionResult="";
if(actionType!=null) {
if(actionType.equals("login")){ // -1-
String userName=request.getParameter("username");
if(userName==null || userName.equals("")){
;
}
else{
String password=request.getParameter("password");
if(password==null)
password="";
testSession ts=
(testSession)session.getAttribute("testSession");
if(ts!=null) { //-1.1-
session.removeAttribute("testSession");
if( !ts.User.name.equals(""))
ts.logout();
}
ts=new testSession();
if(!ts.verify(userName,password)) {
//验证用户与暗码,看是否正当用户
actionResult="login fail";
//犯科用户,显示错误信息
}
else{ //验证乐成
session.setAttribute("testSession",ts);
Vector app_vts=
(Vector)application.getAttribute("app_vts");
if(app_vts==null) {
app_vts=new Vector();
application.setAttribute("app_vts",app_vts);
}
ts.setSessionVar(session.getId(),app_vts);
ts.login(userName);
actionResult=userName+" login success";
}
   }
}
if(actionType.equals("logout")){
testSession ts=
(testSession)session.getAttribute("testSession");
if(ts!=null) {
session.removeAttribute("testSession");
if( !ts.User.name.equals("")){ //-2-
actionResult=ts.User.name;
ts.logout();
}
session.invalidate();
}
actionResult=actionResult+" logout success";
}
}
else
actionResult="null";
%>
<head>
<script LANGUAGE="Javascript"></script>
<script>
function doAction(actionType)
{
document.test.actiontype.value=actionType;
document.test.submit();
}
</script>
</head>
<body>
<table width="80%" border="1" align="center" >
<form method="POST" action="logintest.jsp"
name="test">
<tr>
<td height="33" align="right">用户:</td>
<td width="70%"> <input name="username"
type="text" value="" size="20">
</td>
</tr>
<tr>
<td width="27%" height="22" align="right">暗码:</td>
<td width="73%">
<input name="password" type="password" size="20">
</td>
</tr>
<tr>
<td height="32" colspan="2" align="right">
<div align="center">
<input name="B1" type="button" value="登录"
onclick="doAction('login')">
<input name="B2" type="reset"
value="重写">
<input name="B3" type="button" value="注销"
onclick="doAction('logout')">
&nbsp;</div></td>
</tr>
<tr>
<td width="27%" height="22" align="right">
<input name="actiontype" type="hidden"
value=""></td>
<td width="73%"> <input name="info" type="text"
size="20" value="<%=actionResult%>">
</td>
</tr>
</form>
</table>
</body>

#p#副标题#e#

#p#分页标题#e#

[-1-]:措施的if(actionType.equals("login")){…}部门处理惩罚login。[-1.1-]前后部门先通过session.getAttribute("testSession");取得session中生存的会话变量ts(一个testSession工具实例)。假如ts为空,暗示当前用户还没有login,不然用户已经login了,则先logout再从头login,并将新testSession工具生存到session里。application.getAttribute("app_vts");所取得的变量app_vts中生存了所有当前登任命户的user信息。每个用户login乐成时,即往app_vts中添加一个user工具,这是通过testSession的addappses要领完成的。而当用户注销时,先从session.getAttribute("testSession")中取到当前用户的testSession工具,该工具已含有application.getAttribute("app_vts")工具的引用,通过testSession的logout要领举办注销处理惩罚(见[-2-]标志前后)。TestSession.logout最终是通过挪用removeappses要领从全局工具app_vts中移除用户信息的。总结来说,措施操作应用全局工具application来生存跟踪用户毗连信息的工具(例中为app_vts),该工具记录着应用中所有用户的毗连、退出信息。

JSP页面运行的界面如图:

Java中finalize()的另类用法

当我们输入用户testuser_1并按<登录>按钮,按钮下面的文本框显示"testuser_1 login success"。我们操作viewSessiones.jsp来调查功效,显示如下:

testuser_1 sessionId=A16DCE950C2C664D0AA93E05B27D8E00

viewSessiones.jsp文件的内容如下:

#p#分页标题#e#

<%@ page import="com.testSession, com.user,
java.util.Vector"%>
<%@ page contentType="text/html; charset=GBK"%>
<% request.setCharacterEncoding(response.
getCharacterEncoding()); %>
<%
Vector l_vts=(Vector)application.getAttribute("app_vts");
user l_us;
if(l_vts!=null){
for(int i=0;i<l_vts.size();i++){
l_us=(user)l_vts.get(i);
out.println(l_us.name+" sessionId="+l_us.sessionId);
out.println("<br>");
}
}
%>

viewSessiones.jsp文件的浸染是将app_vts中的用户信息显示出来。

当我们从桌面再启动一个IE措施,输入用户testuser_2并按<登录>按钮,按钮下面的文本框显示"testuser_2 login success"。我们操作viewSessiones.jsp来调查功效,显示如下:

testuser_1 sessionId=A16DCE950C2C664D0AA93E05B27D8E00

testuser_2 sessionId=34B0AF3F1F2573F1C1DD12D62DF06F91

而当我们在第一个IE中按下按钮<注销>,logintest.jsp的显示为:

Java中finalize()的另类用法

#p#副标题#e#

刷新viewSessiones.jsp来调查功效,显示如下:

testuser_2 sessionId=BC487C6A9FD663EA27E797A420B41051

我们在第二个IE中按下按钮<注销>,按钮下面的文本框显示"testuser_2 login success", 刷新viewSessiones.jsp来调查功效,显示出已经没有毗连的用户信息。

上面演示中,用户信息的移除是通过挪用类的logout()要领来实现的。但如果用户没有点按<注销>按钮而直接封锁IE或转到其他网站,该用户信息不是就一直存留在系统中吗?

让我们看看类testSession中的一个要领:

protected void finalize() {
this.removeappses(this.User,this.vsid);
}

用户会见应用,只有一个进口:login。应用的所有用户登录都可以被调查到。用户分开应用,有三种大概:注销、转到其他网站、直接封锁欣赏器。选择注销分开应用,可以被措施调查到(logout),尔后两种方法的分开应用,却不会挪用logout。要调查到后两种方法,就需要利用工具的finalize()要领。

用户通过转到其他网站、直接封锁欣赏器两种方法分开应用高出Session的timeout时间时,用户的Session工具会自动失效,即变为无用工具,而列入了垃圾收集器的接纳范畴;关联的,"寄存"在Session中的testSession工具会同时变为无用工具(在其生命期,仅存在Session对它的引用,Session失效了,它的独一引用者不存在了,也就酿成了无用工具)。垃圾收集器运行时,首先会挪用testSession的finalize(),testSession就通过在finalize()要领中排除app_vts中存储的本用户信息。在testSession类代码中可看到,finalize()挪用类的removeappses()要领执行实际的排除操纵。垃圾收集器的运行,除了让其按照需要自动启动外,也可通过措施挪用来启动它,好比:System.gc() 就直接启动系统垃圾收集行动。

可以想见,本例假如倒霉用类的finalize()要领,我们很难找到另一种轻便的途径来到达排除用户信息的目标,因为用户非正常分开应用的事件对WEB处事端来说是无法感知的。

在testSession类代码中尚有一个较量非凡的处所,实现用户信息插手和排除的两个要领addappses 和removeappses都被界说为static synchronized 范例。为什么呢?这是同步的需要。

App_vts是个应用级的全局可共享工具,在同一时刻毗连到WEB 上的有多个用户,这些用户都可以操纵工具app_vts。假如有两个或以上的用户同时挪用testSession的addappses或removeappses要领(这是完全大概的,因为WEB SERVER是多线程处事),将带来不行预料的功效。

为了防备两个或以上的客户措施(属于差异线程)同时会见一个资源,Java提供了一种内建的机制来办理斗嘴。这种机制就是synchronized(同步)。在一个类中将一个特定的要领设为synchronized(同步的),便可有效地防备斗嘴,在任何时刻,只能有一个线程挪用特定工具的一个synchronized要领(尽量谁人线程可以挪用多个工具的同步要领),另一个线程只有等上一线程对该要领的挪用执行完毕后才气得到该要领的挪用权。大抵的事情机制可以这样认为:每个工具都包括了一把锁(也叫作"监督器"),它自动成为工具的一部门;挪用任何synchronized要领时,工具就会被锁定,不行再挪用谁人工具的其他任何synchronized要领,除非第一个要领完成了本身的事情,并清除锁定。在类testSession中,将 addappses和removeappses这两个要领设为了synchronized,当挪用testSession工具的addappses要领时,便不能再同时挪用testSession工具的removeappses要领,反之亦然。

#p#分页标题#e#

Synchronized又有两个级别。当我们将一个要领仅仅设为synchronized时,那是工具级的"锁",固然一个工具的synchronized要领不行同时挪用,却可以同时挪用差异工具的同一个synchronized要领。所以这样做还没完全办理问题,因为两个用户(各有本身的testSession工具)可以同时挪用addappses要领同时操纵app_vts。当我们将一个要领设为static synchronized时,则是类级的"锁"。类包括的"锁"(自行动为类的Class工具的一部门),可在一个类的范畴内被彼此间锁定起来,从谁人类建设的所有工具都共享一把"锁"。就如testSession实际所做的那样,addappses 和removeappses被界说为static synchronized 范例,这样,任一时候,所有线程用户中必定只能有一个用户挪用addappses 和removeappses两者中的一个要领,到达防备斗嘴的目标。

以上样例在WINDOWS 2000、TOMCAT40、JDK13中通过。

 

    关键字:

天才代写-代写联系方式