Java で, オブジェクト自体にタイムアウト機能を持たせることを考えた. (普通ならば, 外部のオブジェクトが監視するのかな??)

2021.11.30追記: 以下記事が壊れた.

コード

<div class="outline-text-3" id="text-unnumbered-2">
  <p>
    こんなコードを書いた. タイムアウトになったら, 自分自身を Set から削除する.
  </p>
  
  <p>
    [sourcecode language="java" title="" ] import java.util.HashSet; import java.util.Set; import java.util.Collections;
  </p>
  
  <p>
    public class TimeoutObjectSample { public static void main (String[] args) { new B (); } }
  </p>
  
  <p>
    class B { Set<A> set;</p> 
    
    <p>
      public B () { set = Collections.synchronizedSet ( new HashSet<A>() ); A a = new A (this);</p> 
      
      <p>
        set.add (a); System.out.println ("size is " + set.size ()); a.start (); }
      </p>
      
      <p>
        public synchronized Set<A> getSet () { return set; }</p> 
        
        <p>
          }
        </p>
        
        <p>
          class A { B parent;
        </p>
        
        <p>
          public A (B parent) { this.parent = parent; }
        </p>
        
        <p>
          void start () { System.out.println ("start");
        </p>
        
        <p>
          new Thread (new Runnable () {
        </p>
        
        <p>
          public void run () { try{ Thread.sleep (1000); } catch (InterruptedException e){ } finally { Set<A> set = parent.getSet (); System.out.println ("I will die"); set.remove (this); System.out.println ("size is " + set.size ()); } } }).start (); } } [/sourcecode]</p> 
          
          <p>
            しかし, これがうまく動かない. 期待値は最後に Set の要素数が 0 になること.
          </p>
          
          <p>
            [sourcecode language="language" title="" ] size is 1 start I will die size is 1 [/sourcecode]
          </p>
          
          <p>
            もう少し調べてみる. 以下を Thread の内部と外に仕込んだ.
          </p>
          
          <p>
            [sourcecode language="java" title="" ] System.out.println (this); System.out.println (this.getClass ()); [/sourcecode]
          </p>
          
          <p>
            どうも Runnable () クラスの内部と外部では, this を呼んでも別のクラスをさしているようだ.
          </p>
          
          <p>
            [sourcecode language="language" title="" ] size is 1 start A@5df86e79 class A A$1@5f92b8f5 class A$1 I will die size is 1 [/sourcecode]
          </p></div> </div> </div> 
          
          <div id="outline-container-unnumbered-3" class="outline-2">
            <h2 id="unnumbered-3">
              無名クラスに引数を渡す
            </h2>
            
            <div class="outline-text-2" id="text-unnumbered-3">
              <p>
                this でさす内容が違うならば, this をしなければよいのでは?? ということで, 無名クラスにパラメータを渡す方法をしらべる.
              </p>
              
              <p>
                どうやら, 無名クラスのなかに, メソッドを定義すればよいようだ.
              </p>
              
              <ul class="org-ul">
                <li>
                  <a href="https://www58.atwiki.jp/chapati4it/pages/61.html">ちゃぱてぃ商店 IT 部 @ ウィキ - Java/ サンプル/ 無名クラスにパラメータを渡す</a>
                </li>
              </ul>
              
              <p>
                ということで以下を変更
              </p>
              
              <ul class="org-ul">
                <li>
                  無名クラスのなかに, パラメータをうけとる属性を作成
                </li>
                <li>
                  無名クラスのメソッドでパラメータをセットする setter を作成. このメソッドは自分自身 (Runnnable) を返す.
                </li>
                <li>
                  スレッドを起動する前に, パラメータをセットする.
                </li>
              </ul>
              
              <p>
                [sourcecode language="java" title="" ] import java.util.HashSet; import java.util.Set; import java.util.Collections;
              </p>
              
              <p>
                public class TimeoutObjectSample { public static void main (String[] args) { new B (); } }
              </p>
              
              <p>
                class B { Set<A> set;</p> 
                
                <p>
                  public B () { set = Collections.synchronizedSet ( new HashSet<A>() ); A a = new A (this);</p> 
                  
                  <p>
                    set.add (a); System.out.println ("size is " + set.size ()); a.start (); }
                  </p>
                  
                  <p>
                    public synchronized Set<A> getSet () { return set; }</p> 
                    
                    <p>
                      }
                    </p>
                    
                    <p>
                      class A { B parent;
                    </p>
                    
                    <p>
                      public A (B parent) { this.parent = parent; }
                    </p>
                    
                    <p>
                      void start () { System.out.println ("start"); System.out.println (this); System.out.println (this.getClass ());
                    </p>
                    
                    <p>
                      new Thread (new Runnable () { A a; int time;
                    </p>
                    
                    <p>
                      public Runnable setParam (A a, int time) { this.a = a; this.time = time; // 自分自身を返す. return this; }
                    </p>
                    
                    <p>
                      public void run () { try{ Thread.sleep (time); } catch (InterruptedException e){ } finally { Set<A> set = parent.getSet (); System.out.println ("I will die"); set.remove (a); System.out.println ("size is " + set.size ()); } } }.setParam (this, 1000) ).start (); } } [/sourcecode]</p> 
                      
                      <p>
                        これでうまくいきました.
                      </p></div> </div>