ぼんさい塾

ぼんさいノートと補遺に関する素材や注釈です.ミスが多いので初稿から1週間を経た重要な修正のみ最終更新日を残しています.

NetBeansによる演習 (13)

2013-03-30 21:10:19 | 暮らし
progJ.pdf
progJ-s.pdf
progJ-e.pdf

記事一覧

                       wait( ) と notify( ) について

progJ-e.pdf にprogJ.pdf の[#47]に対応する部分を追加しました.

//NowW.java
package myproj;
import mylib.*;
public class Flag {
  boolean w = false;
  synchronized void on( ){
    w = true;
    try{wait( );}catch(Exception e){System.out.println(e);}
  }
  synchronized void off( ){w = false; notify( );}
}
class NowW extends Now {
  Flag f;
  NowW(Flag c, int i){super(i); f = c;}
  public synchronized void run( ){
    f.on( ); super.run( ); f.off( );
  }
  public static void main(String[ ] args){
    Flag f = new Flag( );
    NowW n1 = new NowW(f, 3); n1.start( );
    NowW n2 = new NowW(f, 2); n2.start( );
    try{Thread.sleep(1000);}catch(Exception e){ }
    f.off( );
  }
}


wait()とnotify()-(4)

2013-03-26 19:23:14 | 暮らし
progJ.pdf
progJ-s.pdf
progJ-e.pdf

記事一覧

                      Hello1.java の変更

[1][2]を読んでいないので相互に呼びかけ合うときの適切な例は諦め,最後に Hallo1.java について補足します.
上記のリストは main( ) の変更例で,実行結果は,例えば
  run:
  Skipped?
  name = A
  Hello, A
  name = B
  Hello, B
  構築成功 (合計時間: 10 秒)
のようになります.f.on( ) で wait( ) を実行する前に「f.w = true;」を実行しているにも拘わらず "Skipped?" が出力されるのは,ha.start( ) が Hello1.run( ) を別のスレッドとして起動するだけで,直接 f.on( ) を実行しないことによります.

補足:(1) 先頭に「f.w = true;」を置けばもちろん "Skipped?" は表示されません(きめ細かくタスク管理するには複数の共有変数が必須).
(2) 「ha.start( );」 を 「ha.run( );」 で置換すると main( ) のスレッドで 「wait( );」が実行されて無限ループ(待機状態のまま)になります.
(3) 「ha.run( );」 の位置を変え,ha が選ばれないように「sleep(2000);」を挿入して
  hb = new Hello1(f); hb.start( ); f.off( ); sleep(2000); ha.run( );
としても無限ループです.
(4) 「ha.run( );」の起動より前に「f.off( );」が実行されないように
  hb = new Hello1(f); hb.start( ); sleep(100); f.off( ); sleep(2000); ha.run( );
とすると上記と同様の実行結果が得られます(遅延は泥縄式対策 --- 共有変数で管理したい).

[15] 17.12 スレッド
  http://www.y-adagio.com/public/standards/tr_javalang2/memory.doc.html#28457
  最も高い優先度のスレッドが常に実行されることを保証するものではない。高い信頼性で相互排他を実装するためには,スレッドの優先度を使用することはできない。
[15] 17.14 待機集合及び通知
  http://www.y-adagio.com/public/standards/tr_javalang2/memory.doc.html#28457
  すべてのオブジェクトは,関連するロックをもつだけでなく,関連する待機集合(wait set)をもつ,それは,スレッドの集合とする。・・・・・これらが起こると,スレッド T が待機集合から削除され,スレッドのスケジュール用に再度有効化される。・・・・・したがって,メソッド wait から戻ったときは,オブジェクトのロック状態は,メソッド wait が呼び出されたときと同じになる。
[16] http://www13.plala.or.jp/kymats/study/Java/b16-0.html
  いつスレッドが切り替わるかは環境に依ります。Thread クラスを継承した場合も、Runnable インタフェースを実装した場合も start メソッドを介さず、run メソッドを直接呼び出すことが出来ます。
--------
  それでは、start メソッドを呼び出したときと、run メソッドを直接呼び出したときの動作の違いは何でしょう?
  start メソッドを呼び出した場合、スレッドの実行を開始すると制御は直ぐに戻ってきます。
[17] Javaの道>掲示板(runとstartはどうしてセットで使うのですか?)
  http://www.javaroad.jp/bbs/answer.jsp?q_id=20071214024812799


wait()とnotify()-(3)

2013-03-24 11:41:20 | 暮らし
progJ.pdf
progJ-s.pdf
progJ-e.pdf

記事一覧
             実行結果

共有資源であるコンソール画面の排他制御の例として,現在の時刻を表示する Now とHello2 のオブジェクトを並行して実行するプログラムを示します.Now の run( ) では sleep(4000) を同期する部分の外に置いているので na,nb がほぼ同時に時刻を表示します.
※ f.off( ) を sleep(4000) の後に移動すると表示文字列は変わりませんが4秒遅れて nb が表示されます --- ha より nb が優先されることを示すため sleep(4000) の前に Date( ) を表示(表示文字列も変えたければ,先に sleep(4000) を実行させればよい).

//Hello2.java
package hello;
import java.util.Date;
class Now extends Thread{
  Flag f;
  Now(Flag x){f = x;}
  public synchronized void run( ) {
    f.on( ); System.out.println(new Date( )); f.off( );
    try{sleep(4000);}catch(Exception e){ }
  }
}
public class Hello2 extends Hello {
  Flag f;
  Hello2(Flag x){f = x;}
  void delay(int n){
    try{sleep(n);}catch(Exception e){ }
  }
  public synchronized void run( ){
    while(f.w){delay(100);} // なるべく Now 優先
    f.on( ); super.run( ); f.off( );
  }
  public static void main(String[ ] args) {
    Flag f = new Flag( ); f = new Flag( );
    Now na, nb; Hello2 ha, hb;
    try{
      na = new Now(f); na.start( );
      ha = new Hello2(f); ha.start( );
      nb = new Now(f); nb.start( );
      hb = new Hello2(f); hb.start( );
      //while(f.w){f.off( );} 無効.要 sleep(□);
      sleep(1000); f.off( );
    }catch(Exception e){System.out.println(e);}
  }
}


wait()とnotify()-(2)

2013-03-21 17:56:53 | 暮らし
progJ.pdf
progJ-s.pdf
progJ-e.pdf

記事一覧
  run:
  name = Aoki
  Hello, Aoki
  name = Wada
  Hello, Wada
  構築成功 (合計時間: 12 秒)

下記の単純な Hello.java を実行すると,例えば

  run:
  name = name = okiA
  Hello, okiA
  Wada
  Hello, Wada
  構築成功 (合計時間: 8 秒)

のようになりますが,Hello1.java では上記のように改善されます.
※ get( ) の "name = " で s を読み取って put( ) で "Hello, " + s を表示するより簡単ですね.共有データを get( ),put( ) するときも [4][11] のような構成より [8][9] のようにメソッド内で wait( ) と notify( ), notifyAll( ) を対にする方が無難です --- 読み始めたら書かせない,書き始めたら読ませない.

補足:(1) キー入力があるときは progJ.pdf [#46] のような方法では排他制御できません.なお [#46] の場合 QueS にダミーの int 型フィールド n を設けて「p.n = 1;」としても「p.show( );」のような効果はないことを各自ご確認下さい..
(2) f.on( ), f.off( ) で synchronized ブロック的構成にできます.またboolean型の f.w の代わりにint型の f.k にすると counting semaphore 的に使えます.
(3) Hello1.java の main( ) にある「sleep(2000);」は Hello.java に合わせて挿入したものですが,これを除くと「f.off( );」の実行が早すぎてプログラムが終了しません.この例では末尾に「while(f.w){f.off( );}」を置けば「sleep(□);」を省けましたが,タイミングが悪いと効かないこともあります.

//Hello.java
project hello;
import java.io.*;
public class Hello extends Thread {
  String s;
  public synchronized void run( ){
    BufferedReader r;
    try{
      System.out.print("name = ");
      r = new BufferedReader(new InputStreamReader(System.in));
      s = r.readLine( );
      System.out.println("Hello, " + s);
    }catch(Exception e){System.out.println(e);}
  }
  public static void main(String[ ] args) {
    Hello ha, hb;
    try{
      ha = new Hello( ); ha.start( ); sleep(2000);
      hb = new Hello( ); hb.start( );
    }catch(Exception e){System.out.println(e);}
  }
}
----------------------------------------------------
//Hello1.java
project hello;
import java.io.*;
class Flag{
  boolean w; //waiting
  Flag( ){w = false;}
  synchronized void on( ){
    try {w = true; wait();}catch(Exception e){System.out.println(e);}
  }
  synchronized void off( ){
    w = false; notify( );
  }
}
public class Hello1 extends Hello {
  Flag f;
  Hello1(Flag x){f = x;}
  public synchronized void run( ){
    f.on( ); super.run( ); f.off( );
  }
  public static void main(String[ ] args) {
    Hello1 ha, hb; Flag f = new Flag( );
    try{
      ha = new Hello1(f); ha.start( ); sleep(2000);
      hb = new Hello1(f); hb.start( ); f.off( );
    }catch(Exception e){System.out.println(e);}
  }
}


wait()とnotify()-(1)

2013-03-19 17:45:27 | 暮らし
progJ.pdf
progJ-s.pdf
progJ-e.pdf

記事一覧

                 Synchronized Statements [2]

progJ-e.pdf にprogJ.pdf の[#47]に対応する部分は Now や QueR のサブクラスで演習する予定ですがwait( ), notify( ) の使い方が分かり難いので,独立した Hello のサブクラスで少し詳しく説明します(progJ-e.pdf では割愛).なお,上図のようにメソッド内のブロックだけを「synchronized」にすることもできますが,以下では簡単のためメソッド全体を「synchronized」にします.

本格的に勉強したい人は [1],[2] を読んでください.手抜きで「wait notify 使い方」や「wait notify tutorial」を Google で検索すると[3]~[14] 等が見つかります.使い方の例は一つのメソッドに notify() と wait() が対になったものとそうでないものに大別できます --- 前者の構成を基本にする方が分かり易いと思います.後者の構成は,例えば [4] では解決済みの回答として

  public class SomeData{
   synchronized void get( ){if(空){wait( );} /* データ取得処理 */}
   synchronized void put( ){/* データ収納処理 */ notify( );}
  }

が示されています.この構成で [11] の処理を

  public class Hishi extends Thread {
    Object lock; int k;
    void msleep(String s, int ms){//予測
      try{
        System.out.println(s +" sleep"+ ms +" start");
        Thread.sleep(ms);
        System.out.println(s +" sleep"+ ms +" end");
      }catch(Exception e){ }
    }
    public void thread1( ) {//原文どおり
      System.out.println("W1 start");
      synchronized (lock) {
        System.out.println("W1 lock start");
        msleep("W1",200);
        try {
          System.out.println("W1 wait start");
          lock.wait( );
          System.out.println("W1 wait end");
        } catch (InterruptedException e) {
        }
        msleep("W1",1000);
        System.out.println("W1 lock end");
      }
      System.out.println("W1 end");
    }
    public void thread2( ) {//原文どおり
      System.out.println("W2 start");
      synchronized (lock) {
        System.out.println("W2 lock start");
        msleep("W2",100);
        System.out.println("W2 notify start");
        lock.notify( );
        System.out.println("W2 notify end");
        msleep("W2",1000);
        System.out.println("W2 lock end");
      }
      msleep("W2",1000);
      System.out.println("W2 end");
    }
    public synchronized void run( ){//手抜き
      lock = new Object( );
      if(k == 1){thread1( );}
      else if(k == 2){thread2( );}
      else{
        try{sleep(5000);}catch(Exception e){ }
        notifyAll( );
        System.out.println("notifyAll( ) end");
      }
    }
    public static void main(String[ ] args) {
      Hishi h0, h1, h2;
      h0 = new Hishi( ); h0.k = 0; h0.start( );
      h1 = new Hishi( ); h1.k = 1; h1.start( );
      h2 = new Hishi( ); h2.k = 2; h2.start( );
    }
  }

と具体化すると原文と類似の実行結果が得られます.多くの資料を読み比べるのをサボって「自分で調べるCのポインタ」 と同様「自分で調べる Java のスレッド」として NetBeansIDE を使って Hello.java のサブクラスを考えて見ましょう.

[1] Java言語規定 第2版 / 17. スレッド及びロック
  http://www.y-adagio.com/public/standards/tr_javalang2/memory.doc.html#30206
 (17.13 ロック及び同期,17.14 待機集合及び通知,etc.)
[2] The Java Tutorials / Concurrency / Synchronization
  http://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html
  {syncmeth.html, locksync.html, deadlock.html, guardmeth.html, etc.}
--------
[3] [java wait]についての検索結果 ( 約55件中 1~10件を表示 ) - 教えて ...
  http://oshiete.goo.ne.jp/search_goo/result?code=utf8&MT=java+wait
[4] javaのwaitしてるスレッドをnotifyで起こすことが出来ない | JavaのQ&A ...
  http://okwave.jp/qa/q4542536.html
  http://oshiete.goo.ne.jp/qa/4542536.html
  http://soudan1.biglobe.ne.jp/qa4542536.html
[5] Java 入門 | wait()/notify() - FC2Web
  http://msugai.fc2web.com/java/thread/waitnotify.html
[6] Javaの道>掲示板(wait()の使い方)
  http://www.javaroad.jp/bbs/answer.jsp?q_id=20090222134150310
[7] コマンド終了待ち時のタイムアウト処理 - Java Solution - @IT
  http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=33873&forum=12
[8] 5. スレッドの同期 (2) | TECHSCORE(テックスコア)
  http://www.techscore.com/tech/Java/JavaSE/Thread/5-2/
[9] Javaの道:スレッド(4.スレッドの同期)
  http://www.javaroad.jp/java_thread4.htm
[10] Java Program Examples / 相互に干渉するスレッドの実行
  http://bach.istc.kobe-u.ac.jp/java/examples/Ex0211a.java
[11] Javaスレッドメモ(Hishidama's Java thread Memo)
  http://www.ne.jp/asahi/hishidama/home/tech/java/thread.html
[12] wait(), notify() and notifyAll() in Java - A tutorial
  http://www.java-samples.com/showtutorial.php?tutorialid=306
[13] A good small example to demonstrate wait() and notify() method in java
  http://stackoverflow.com/questions/8358600/
[14] How do I use the wait() and notify() methods? - Web Tutorials ...
  http://www.avajava.com/tutorials/lessons/how-do-i-use-the-wait-and-notify-methods.html