同期化を使用した場合に値をソート化して処理を実行することは可能でしょうか?

このQ&Aのポイント
  • Collections.synchronizedListを使用してサーブレットでの同期化を実行しています。
  • Collections.synchronizedSortedSetを使用してラップオブジェクトを同期化しています。
  • 実行させたい順序はC→A→Bです。どのキーに対しての処理中かを見ることはできないようです。
回答を見る
  • ベストアンサー

同期化時のことで

いつもお世話になっています。 同期化を使用した場合のことで質問します。 private static final List<String> list = Collections.synchronizedList(new ArrayList<String>() ); を使いサーブレットでの同期化を実行しているのですが、 この場合に、値をソート化して処理を実行することは可能なのでしょうか? Collectionsを調べると、可能性としてsynchronizedSetだとできそうな気はするのですが、 その際の直列化の実装がよくわかりません。 考えているソースは以下です。 ** ラップオブジェクト同期化 **/ SortedSet sort = Collections.synchronizedSortedSet(new TreeSet<String>() ); /** サーブレットクラスでの処理 **/ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //リクエストデータ String key = request.getParameter("key"); //リクエストデータをSortedSetに格納する sort.add(key); //←この時点で、直列化のための何らかの処理がいる try{ //実行時、時間をずらすために宣言 Thread.sleep(1000); }catch(Exception e){ } //何の処理もしなかったら、実行された画面の順で処理が開始される synchronized(sort){ for(int a=0;a<10;a++){ System.out.println("a="+a); } } //SortedSetに格納された値の順 List sortList = new ArrayList(sort); for(int s=0;s<sortList.size();s++ ){ //↓すべての処理が終わってみたら、確かにソート化されているs System.out.println("sortList["+s+"]="+sortList.get(s)); } } jsp側のリクエストデータ 1回目 C 2回目 B 3回目 A 実行させたい順 C→A→B このとき、B,Aが渡されるタイミングは、Cの処理が実行中時 また、どのキーに対しての実行中なのかを見ることはできるのでしょうか? Collectionsクラスを見たところなさそうだったのですが。。。 宜しくお願いします。

  • Java
  • 回答数4
  • ありがとう数0

質問者が選んだベストアンサー

  • ベストアンサー
回答No.4

◆ AddDev.java ◆ protected void doPost( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String userID = request.getParameter("userID"); //渡される引数はログイン中のid //userIDをデーターベースに書き込む //ユーザーキーを遷移先に渡す request.setAttribute("userID",userID); //処理実行側に遷移する getServletContext().getRequestDispatcher("/sample/end.jsp").forward(request,response); } ◆ end.jsp ◆ String userID = (String)request.getAttribute("userID"); //↑サーブレットから渡されてきたuserID nm:while(true){ List list = runJyunjyo(); // runJyujyo 実行ユーザーリストをデータベースに問い合わせるメソッド if ( list.get(0).equals(userID) ) { //処理実行 //処理が完了したら、自分のuserIDデータベースから削除する }else { //一定時間間隔スリープする } } …ではどうでしょう。 JMS(キュー)のイメージで例えると、「userIDをデーターベースに書き込む」ところが要求メッセージをput、「実行ユーザーリストをデータベースに問い合わせる」ところが要求が処理可能になるまでpeekする、「処理が完了したら、自分のuserIDデータベースから削除する」ところが完了した要求メッセージをgetするという感じです。 ちなみに、このプログラムは、同じuserIDが重複して処理を要求されないことを前提としています。 :-) userIDが重複するような場合は、データベースへ書き込む際に受付番号みたいなものを発行して、その受付番号をuserIDの代わりに渡すなどの工夫が必要になります。

その他の回答 (3)

回答No.3

> 複数ページからアクセスされる場合のことを考えたのですが、 > どうすればアクセス順にメッセージが返されるのかがいまいちつかめません。 そうですねぇ。JMSはもともとFIFO(先入れ先出し)で利用されることを中心に想定されてますので、キーの昇順に検索とか、複雑な条件で検索とかになると、JMSはあまり得意ではありません。 そのような場合、JMSを利用してそういうロジック(peekMessage()などで全メッセージを舐めて、該当するメッセージを受信するようなプログラム)を自分で実装してやらなければならなくなります。 優先順位付けしたりや関連IDやキュー名で分類したり、あるいはメッセージセレクタ(メッセージ属性を対象とした条件記述)はあるですが、やはりRDBのSQLと比較すると見劣りします。 この辺りにもJMSがいまひとつ普及しない理由があるのかもしれませんね。 > 柔軟というのが、理解できるのですが、タイミングや実行プロセスの変更はどうすればできるのでしょうか? あくまでそのような構成も構築可能というだけの話です。 私が少しはなしを広げすぎたかもしれません。 ここでいっているタイミングや実行プロセスの変更とは、以下のような状況を想定していっています。 恐らく今考えられているシステムでは、サーブレット側(Webサーバ?)で受け付けた要求を、JSP側(Appサーバ?)に処理を実行させ、完了確認画面(ページ)を何回か見にいくと完了していることが確認できるというような流れではないでしょうか。 もしも後から、JSP側を複数台構成に増強したくなったり、フェールオーバー構成にしたくなった場合に、要求側/応答側の間があまり親密な関係にあると、可能な選択肢が狭まってしまいます。 あるいは、極端に処理時間がかかるような処理は、処理負荷の低い時間帯に実行させるように、別途スケジューラやバッチ処理で実行させるように変更したくなるかもしれません。 このような場合でもデータベース上で要求/完了を管理していれば、当初の想定にない実行環境であっても、たとえそこで使える開発言語がJavaでなくても、まぁ何とか連携できるようにできる可能性が一番高いでしょう。 ただ、あまりそのような可能性がないようであれば、とりあえず気にしすぎることはないかもしれません。 ちなみにこの辺りの話は「疎結合」といったキーワードで検索するともっと詳しい説明がみつかるとおもいます。

kannitiha
質問者

補足

詳しい説明ありがとうございます。 あれから、回答を見て、考えてみたのですが、 たとえば以下の考え方だとどうなのでしょうか? ex) Top.jsp → サーブレット(AddDev.java) → 処理順番をBeanクラスに渡す(UserAdmin.java) → 実行jspに遷移させる(end.jsp) ーーー 作成ソース ---- ◆ Top.jsp ◆ <form action="./../AddDesc" method="POST"> <input type="text" name="id" value=""> <input type="submit" value="ログイン"> </form> ◆ AddDev.java ◆ private List listSample = new ArrayList(); protected void doPost( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String userID = request.getParameter("userID"); //渡される引数はログイン中のid //userIDをデーターベースに書き込む //データーベースより実行ユーザーを取り出して、listに格納 this.listSample = runJyunjyo(); // runJyujyo 実行ユーザーリストをデータベースより取り出すメソッド //共有Beanクラスに格納 UserAdmin user = new UserAdmin(); user.setListUser(listSample); //ユーザーキーを遷移先に渡す request.setAttribute("userID",userID); //結果を遷移する getServletContext().getRequestDispatcher("/sample/end.jsp").forward(request,response); } ◆ UserAdmin.java ◆ public static class UserAdmin { public static List listA = new ArrayList(); /** * 実行ユーザーを設定する */ public void setListUser(List list){ this.listA = list; } /** * 実行中ユーザーをチェックする */ public static boolean getIsCheckRunUser(String userID){ //最初のユーザーが等しいならtrueを返す if(listA.get(0).equals(userID)){ return true; }else{ return false; } } } ◆ end.jsp ◆ String userID = (String)request.getAttribute("userID"); //↑サーブレットから渡されてきたuserID nm:while(true){ //UserAdminクラスに実行順番が決まるまで待機させる boolean isCheckRunUser = UserAdmin.getIsCheckRunUser(userID); if(isCheckRunUser == true){ //処理実行 }else { //trueになるまで処理しない } } 宜しくお願いします。

回答No.2

> 説明時の、「メッセージキュー」というのは、 > http://liffey2.ld.infoseek.co.jp/java/jms/のようなことなのでしょうか? そうです。 >この際にjavax.jmsパッケージがあるのですが、これはすでにjava自体が持っているのでしょうか? javax.jmsは、標準化されたAPIです。 実際に利用するためには、JMSプロバイダ(サーバ)が必要になります。 データベースにたとえると、javax.jmsはjdbcのようなもので、実際に利用するためには、(OracleやMySQLのような)DBMSを用意する必要があるようなものです。 >また、JMSというのは、 >http://cgi.search.biglobe.ne.jp/cgi-bin/search-tb43n?jc=%B8%A1%BA%F...でヒットするサイトのようなことと思えばいいのでしょうか? そうです。Java Messaging Service のことです。 メジャーなところではActiveMQやJBossMessagingなどがあります。 あるいはWebSphereMQのようなMQ製品や、あるいは、OracleのようなRDBMS製品もJMS(のAPI)でアクセスできるインターフェースを用意していたりします。

kannitiha
質問者

補足

回答ありがとうございます。 実際にActiveMQのほうで試してみました。 メッセージの送受信のイメージは何とかつかめました。 JMSには2種のパターンがあり、 1.point-to-point → 送信者と受信者が1対1の関係 2.Publisher-Subscriber →送信者1に対し受信者が複数の関係 このとき、2のPublisherの方で、 http://www.techscore.com/tech/J2EE/JMS/3.htmlを参考にして、 複数ページからアクセスされる場合のことを考えたのですが、 どうすればアクセス順にメッセージが返されるのかがいまいちつかめません。 なんとなく、Publisherクラスの TextMessage msg = session.createTextMessage()のあたりと、 SubcriberクラスのTextMessage msg = (TextMessage)subscriber.receive(); のあたりに理由がありそうな気はするのですが。 したいのが、以下のような形です。 画面から渡されてくる値と順番を以下とする 1回目 summer 2回目 winter 3回目 automne 使用するdbテーブル create table userName ( num integer not null primary key, userName varchar(10) not null ); 実行順ユーザーをセレクトするsql select * from userName order by userName asci where userName='!実行中のユーザー名'; sql文で取得された順番で結果がそのページへ返される つまり、 1回目→3回目→2回目のアクセス順で結果が返される synchronized()を使用した場合だと、 1回目→2回目→3回目にアクセスされた順に結果が返される この場合に、 >また、要求の順番についても検索SQLを書き換えるだけなので柔軟性も確保できますし、 処理を実行する側も同じDBを見に行けばよいだけなので、 >処理を実行するタイミングや実行するプロセスも柔軟に変更することができます。 柔軟というのが、理解できるのですが、タイミングや実行プロセスの変更はどうすればできるのでしょうか? 宜しくお願いします。

回答No.1

やりたいことは、受け付けた要求を、何らかのルールに従って順番に処理を行いたいということですね? 一般論から話をすると、このような処理方式はメッセージ駆動型と呼ばれ、そのためのデータ構造はメッセージキューと呼ばれます。 メッセージキューは、1スレッドのみがアクセスするか?複数スレッドがアクセスするか?複数プロセスがアクセスするか?あるいは、メッセージは永続化されるか?トランザクション性は必要か?などにより様々な実装が存在します。 たとえば、Swingのイベントキューやjava.util.concurrentのキューや、JMSもメッセージキューです。 Java以外でも、Windowsのウインドウメッセージキュー、POSIXのメッセージキュー、MQ製品などがあります。 一方、synchronizedは、どちらかというと排他制御を簡単に扱えることを目的としたものですので、待たされている要求の情報や、今実行中のメソッドなどの情報を取得することはあまり想定されていません。。 javaのCollectionをsynchronizedでアクセスすることでカスタムのメッセージキュー実装とすることができなくはありませんが、実装するためには、様々な並列処理の問題(デッドロックが発生しないか?適切なスコープで排他されているか?排他スコープはどのように管理・アクセスするか?)などの問題について相応のスキルが必要となります。 また、サーブレットからの実行ということなので、話はさらに厄介ですね。アプリケーションサーバ毎に実装を変えなければならないかもしれません。 実装方式や実装上の注意点などは、あまりにも沢山ありすぎて、実装方式ごとに本が書けそうなぐらいです。 私がここでいえることは、そのような無茶はしないほうがいいということです。 その代わり、次のような代替案はいかがでしょう。 どのようなシステムを実装しようとしているかは分かりませんが、サーブレットということなので、いずれかのリレーショナルデータベースは既に使っているのではないでしょうか? もしそうであれば、RDB上に要求受付用のテーブルを用意して、これをメッセージキューとして利用するという方法があります。 javaオブジェクトのみで処理するよりは多少パフォーマンスが落ちますが、その代わりに、並列処理の問題のほとんどをDBMSが肩代わりしてくれます。 また、要求の順番についても検索SQLを書き換えるだけなので柔軟性も確保できますし、処理を実行する側も同じDBを見に行けばよいだけなので、処理を実行するタイミングや実行するプロセスも柔軟に変更することができます。 実際のところ、JMSやMQ製品はメッセージキューを実現している特殊なデータベースということもできるぐらいです。 それどころか、JMSの実装には、内部でオープンソースのRDBを利用しているものが多く存在しているぐらいです。 そう考えれば、難しい並列処理の実装をしたり、新たにJMSについて勉強するより、要求受付テーブルを1つ実装する方が簡単だとはおもいませんか?

kannitiha
質問者

補足

丁寧な説明ありがとうございます。 説明時の、「メッセージキュー」というのは、 http://liffey2.ld.infoseek.co.jp/java/jms/のようなことなのでしょうか? この際にjavax.jmsパッケージがあるのですが、これはすでにjava自体が持っているのでしょうか? また、JMSというのは、 http://cgi.search.biglobe.ne.jp/cgi-bin/search-tb43n?jc=%B8%A1%BA%F7&q=java+JMS&num=10でヒットするサイトのようなことと思えばいいのでしょうか? 宜しくお願いします。

関連するQ&A

  • Collections.binarySearchについて

    Collections.binarySearchを使うには、ソートする必要があることがわかりますが、ソートしない場合、結果はどうなるのはちょっと気になってしまっているので質問させてください。 例:public class char6_33 { public static void main(String args[]){ List list=new ArrayList(); list.add("b"); list.add("a"); list.add("c"); System.out.println(Collections.binarySearch(list,"a")); System.out.println(Collections.binarySearch(list,"b")); System.out.println(Collections.binarySearch(list,"c")); } 実行してみたら、結果は 1 -3 2 になるですが、なぜでしょうか。 もしSystem.out.println(Collections.binarySearch(list,"a"));の前にCollections.sort(list);を追加すれば、結果は0 1 2になるのは理解するできが、ソートしない場合はなぜ1 -3 2 になるのはちょっと理解できません。ご存知の方はぜひご教授ください。よろしくお願いします。

  • コレクションクラスについて

    ●下記のコードについて質問があります import java.util.*; public class Test { public static void main(String args[]) { ArrayList<ObjectOne> list = new ArrayList<ObjectOne>(); list.add(new ObjectOne()); list.add(new ObjectOne()); list.add(new ObjectOne()); Collections.sort(list); } } class ObjectOne { private int x = 0; private int y = 0; } このソースをコンパイルすると、 シンボル: メソッド sort(java.util.ArrayList<ObjectOne>) 場所 : java.util.Collections の クラス Collections.sort(list); と、エラーが表示されてしまいます。 java.util.*をインポートしているので、上記のようなエラーはでないと 思うのですが、うまくいかないです。おそらく、ObjectOneクラスで 何か処理漏れが起きているのかもしれませんが、エラーとなる原因を 特定することができません。 エラーとなる原因と解消する手立てを教えていただければと思っております。 宜しくお願い致します。 「追記」 ArrayList<ObjectOne> list = new ArrayList<ObjectOne>(); の<ObjectOne>を消せばエラーはなくなりますが、 <ObjectOne>を消さない方針で考えがあればと思っております。

  • ★Java1.5 オブジェクトのソートについて ソートキーを2つ指定する方法★

    困っています。ご存知の方教えてください。 リスト(ArrayList<UserBean>)の中に、 以下の用に2つのプロパティを持つBeanオブジェクトがが複数入っています。 --------------- UserBean{ private String name; private String no; // setter getter は省略 } --------------- このリストの中に入っているオブジェクトをソートしたいのですが、うまい方法が見つかりません。 また、ソートを行うにあたって2つのキーを指定してソートしたいです。 (第1優先Key = name 第2優先Key = no) keyが1つのソートであれば、jakarta commonsのクラスを利用して、このように (Collections.sort( list , new BeanComparator("name"));) ソートできたのですが、 ソートキー2つとなると手が止まってしまいました・・・。 commonsのクラスで2つキーを指定する方法もあるのでしょうか。 簡潔にオブジェクトをソートできる方法ご存知の方いましたらご教授下さい。 お願いいたします。

    • ベストアンサー
    • Java
  • JAVA LIST ソート

    JAVA LIST ソート JAVAの初心者です。よろしくお願いします。 検索結果の一覧画面のデータを SORT ボタンをクリック時、JAVA側で セッションBEANに保持してる 画面一覧のLISTデータをあるキーでソートしたいですが、 わからなくて困ってます。 自分なり考えたのは、 ArrayList list = new ArrayList(); List.add(getSessionBean());ーーーセッションBEANのデータをリストに追加 Collections.sort(list, new MyComparator() ここで MyComparator()での書き方がよくわかりません。 もし、ソートキーが 複数あれば どうなりますか? サンプルなどがあれば、ご教授頂ければ幸いです。

  • 非常に初歩的な質問で恐縮なのですが、

    非常に初歩的な質問で恐縮なのですが、 C#で、配列リストを機械的に複数個作ることはできないでしょうか。 具体的には、myArrayListという配列リストを100個作るとして、 System.Collections.ArrayList myArrayList1 = new System.Collections.ArrayList(); System.Collections.ArrayList myArrayList2 = new System.Collections.ArrayList(); System.Collections.ArrayList myArrayList3 = new System.Collections.ArrayList(); System.Collections.ArrayList myArrayList4 = new System.Collections.ArrayList(); System.Collections.ArrayList myArrayList5 = new System.Collections.ArrayList(); ・・・ System.Collections.ArrayList myArrayList100 = new System.Collections.ArrayList(); をループなどを使うことによって書きたいのですが。 詳しい方がいらっしゃいましたら、アドバイス願います。

  • C#の配列リストを機械的に複数作りたいです。非常に初歩的な質問で恐縮な

    C#の配列リストを機械的に複数作りたいです。非常に初歩的な質問で恐縮なのですが、 C#で、配列リストを機械的に複数個作ることはできないでしょうか。 具体的には、myArrayListという配列リストを100個作るとして、 System.Collections.ArrayList myArrayList1 = new System.Collections.ArrayList(); System.Collections.ArrayList myArrayList2 = new System.Collections.ArrayList(); System.Collections.ArrayList myArrayList3 = new System.Collections.ArrayList(); System.Collections.ArrayList myArrayList4 = new System.Collections.ArrayList(); System.Collections.ArrayList myArrayList5 = new System.Collections.ArrayList(); ・・・ System.Collections.ArrayList myArrayList100 = new System.Collections.ArrayList(); をループなどを使うことによって書きたいのですが。 詳しい方がいらっしゃいましたら、アドバイス願います。 同じ内容の質問を先ほど投稿してしまったのですが、タイトルが不適切だったため 直させていただきました。すいませんでした。

  • [Java]多重のジェネリクス

    ジェネリクスの仕様を知らないだろう、無知な質問です。  List<List<String>> list_a = new ArrayList<List<String>>(); は可能ですが。  List<List<String>> list_b = new ArrayList<ArrayList<String>>(); はできません。 できなくて困ることはないのですが これが、なぜできないかが理解できません。 コンパイラにはどのように見えているのでしょうか?

  • jspのListのListの表現方法について

    Listの中にListを入れる処理をJava側でしています。 そのListをリクエストに投げているのですが JSPでの表現方法がわかりません。 Java側では ArrayList[] a_list = new ArrayList[10]; a_list[j]= new ArrayList<Dto>(); a_list[j].add(list.get(i)); という感じで作っています。 logic:iterateをネストしても うまく取れません。 どなたか、分かりましたら、よろしくお願いします。

    • ベストアンサー
    • Java
  • HashMap要素の操作について

    過去質問を検索致しましたが、適当な質問を見つけられなかった為、質問をさせて頂きます。 ●下記コードのうち、AブロックとBブロックとでどのように異なる為、 Aブロックの値操作が、そのままHashMapへ反省されてしまうのかをご教示願えませんでしょうか? コメント"Aブロック"部分でのArrayList型変数へ操作した内容は、そのままHashMap内の当該キー要素に反映されてしまいます。 コメント"Bブロック"で行う、String型への操作は、HashMap内の当該キー要素に反映はされません。 ■実行環境 ・jdk1.3.1_11 ・Windows XP pro SP2 _________________________________________________ HashMap testMap = new HashMap(); // マップへArrayListとStringを追加 testMap.put("KEY_LIST", new ArrayList()); testMap.put("KEY_STRING", "stringVal"); // Aブロック ArrayList testList = (ArrayList) testMap.get("KEY_LIST"); testList.add("one"); testList.add("two"); testList.remove(0); // Bブロック String testString = (String) testMap.get("KEY_STRING"); testString = "one"; testString = ""; _________________________________________________

    • ベストアンサー
    • Java
  • 九九の表の応用

    Java勉強中の超初心者です。 ちょっと前に同じ質問をしたのですが、前回の回答をよく見たら 趣旨とは違った処理をしていたのでもう一度、質問をさせて下さい。 ArrayListを使った九九の表を作成します。 この時に、九九の計算結果を一旦、Stringの配列に格納してから、 ArrayListから値を出力します。 この時にArrayListに格納してから出力するソースは書くことが できたのですが、一旦、格段はString[]s = new String[9];として Stringの配列に格納してから、ArrayListにまとめて出力する方法 をご教授お願いできますか? ----------------------------------------------------------- ArrayList list = new ArrayList(); //ここにString[]s = new String[9];が入ります。 for(int i = 1; i <= 9; i++ ){ for(int j = 1; j <= 9; j++){ list.add(i*j); System.out.print(list.get(list.size() - 1) + " "); if((list.size() - 1) % 9 == 8 && (list.size() - 1) != 0){ System.out.println(""); } } } ---------------------------------------------------------- 上記のソースを元に作成できたらと、思います。

    • ベストアンサー
    • Java

専門家に質問してみよう