まず、概念
JSPや他のスクリプト言語は、JSPのデフォルトのモードを同時に実装における問題の変数を読み込むため、複数のユーザがあるかもしれない、マルチスレッド実行です。
クラス変数、インスタンス変数、ローカル変数の関係を初めて目。
1.クラス変数
のリクエスト、レスポンス、セッション、設定ファイル、アプリケーション、 およびJSPページは、内蔵のpageContext、ページ。
どのアプリケーションに加えて、他のは、スレッドセーフです。
2.インスタンス変数の
インスタンス変数は、ヒープ上の割り当ての全ての例です。サーブレット/ JSPコンテナに、一般のみサーブレット/ JSPのインスタンスをインスタンス化し、
要求を処理するためにインスタンスの複数のスレッドを起動します。インスタンス変数は、すべてのスレッドがインスタンスを共有している、インスタンス変数はスレッドセーフではありません。
3.ローカル変数
ローカル変数は、スレッドセーフであるように、各スレッドは、独自の実行スタックを持っているので、ローカル変数は、スタックに割り当てられます。
JSPのローカル変数で定義されたインスタンス変数とメソッド:
<%!%>内の変数とメソッドは、メンバ変数とメンバメソッドでクラス内の変数やメソッドです。
<%%>内の変数はローカル変数であるプロセス変数です。
第二に、問題
次のコードを見てください
<!% @ インスタンス変数を定義する 文字列のユーザ名; 文字列のパスワード; てjava.io.PrintWriter出力; %> <% @ リクエストから取得パラメータ 名= request.getParameter( "ユーザ名" ); パスワード = request.getParameter( "パスワード" ); 出力 = response.getWriter(); showUserInfo(); %> !<% 公共のボイドshowUserInfo(){ // 同時実行の問題を強調するために、ここで最初に実行する時間のかかる操作のINT I 0 =、J = 0、 = 0 K ; ダブル SUM = 0.0 ; 一方 (I ++ <999999999 ){ 一方(J ++ <999999999 ){ 一方(K ++ <999999999 ){ 合計 + = I。 } } } output.println(にThread.currentThread()のgetName() + "<BR>" )。 //获取当前进程的名称 output.println( "ユーザ名:" +ユーザー名+ "<BR>" ); output.println( "パスワード:" +パスワード+ "<BR>" ); } %>
このページでは、我々は、最初の2つのインスタンス変数、ユーザー名とパスワードを定義します。そして、リクエストから2つのパラメータを取得し、顧客のブラウザ上の要求ユーザ情報のエコーにshowUserInfo()メソッドを呼び出します。ときに、ユーザー訪問、問題は存在しません。しかし、複数のユーザーの同時アクセス、いくつかの他のユーザーのブラウザ上の他のユーザの情報表示に問題があるでしょう。これは深刻な問題です。ハイライトの並行性の問題、テストの容易さ、観察するために、我々は、例えば、時にシミュレートされたユーザ情報のエコー時間のかかる操作を行って、次の二つのユーザーが同時に(IEブラウザが同時にアクセス2を開始することができます):
http:// localhostを:8080/3 / 1.jspユーザ名=&パスワード= 123? のhttp:// localhostを:?3分の8080 / 1.jspユーザ名= B&パスワード= 456
あなたは、bの後のリンクをクリックして、リンクをクリックすると、その後、空白の画面に戻るだろう、あなたは出力BとBを取得する二つのスレッドです。
上記のプログラムの出力、ユーザ名とパスワードは、インスタンス変数はすべてのスレッドで共有されているためです。ページを訪問した後、出力は、ユーザ名の出力に設定され、パスワードは設定情報Aあり、ユーザー名とパスワードの情報を出力する前に、bはページ、ユーザー名とパスワードを訪れた()でprintUserInfoを行っています出力点Bに情報B、および出力を設定します。印刷するときに、Bをスクリーニングするために印刷するスレッドが続き、そして、ユーザ名とパスワードもBに置き換えられています。
実際のインターバル時間は、2つの操作が非常に短くする必要があり、この問題は、訪問の際に多数発生する可能性があります。
第三に、ソリューション
1から渡されたインスタンス変数、パラメータを削除
コードは以下の通りです
<% //使用局部变量 String username; String password; java.io.PrintWriter output; //从request中获取参数 username = request.getParameter("username"); password = request.getParameter("password"); output = response.getWriter(); showUserInfo(output, username, password); %> <%! public void showUserInfo(java.io.PrintWriter _output, String _username, String _password) { //为了突出并发问题,在这儿首先执行一个费时操作 int i =0,j=0,k=0; double sum = 0.0; while (i++ < 999999999) { while(j++<999999999){ while(k++ < 999999999){ sum += i; } } } _output.println(Thread.currentThread().getName() + "<br>"); _output.println("username:" + _username + "<br>"); _output.println("password:" + _password + "<br>"); } %>
运行结果如下:
通过定义局部变量,并参数进行传递。这样,由于局部变量是在线程的堆栈中进行分配的,所以是线程安全的。不会出现多线程同步的问题
2.以单线程方式运行
JSP界面设置如下
<%@page isThreadSafe="false"%>
默认为true,是多线程模式
如果将JSP或Servlet设置成单线程工作模式,会导致每个请求创建一个Servlet实例,这种实践将导致严重的性能问题(服务器的内存压力很大,还会导致频繁的垃圾回收),所以通常情况下并不会这么做。
参考: