• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:同期化時のことで)

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

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

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

  • ベストアンサー
回答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