Two-Phase Termination(interrupt版) →失敗

javaにおけるThread#interruptのような「wait/sleep状態のスレッドを中断させるメソッド」というものが分からなかったので、その点を省略しています。

http://d.hatena.ne.jp/qnzm/20080209/1202524095

と言っていたのですが、単純に例外投げるようThread拡張すればいいような気がしてきました。

Object クラスの wait()、wait(long)、wait(long, int) メソッドの呼び出し、またはこのクラスの join(), join(long)、join(long, int)、sleep(long)、または sleep(long, int) メソッドの呼び出しでこのスレッドがブロックされる場合、割り込みステータスはクリアされ、InterruptedException を受け取ります。

Thread (Java 2 プラットフォーム SE v1.4.0)

Javaでも、interrupt呼び出されたらその場でInterruptedExceptionが発生するわけですし。
その前提で、前のソースを一部調整してみました。

require 'thread'
require 'monitor'

class Thread
  def interrupt
    raise Interrupt
  end
end

class Logger
  include MonitorMixin

  def initialize
    @t = nil
    @started = false
    @finished = false
    super()
  end
  def start
    synchronize do
      return if @started || @finished
      log = "out.log"
      File.delete(log) if File.exists?(log)

      @t = Thread.start do
        until @finished do
          File.open(log, 'a') do |w|
            begin
              w.puts "<<#{Time.now}>>"
              for i in 1..9 do
                w.print rand(i)
              end
              w.print "\n"
              sleep(1) #重い処理
              w.puts "--------------"
            rescue Interrupt
              @finished = true
            ensure
              next
            end
          end
        end
        puts "<<Exit Thread>>"
      end
      @started = true
    end
  end
  def interrupt
    @t.interrupt
  end
  def stop
    return unless @started
    return if @finished
    self.interrupt
  end

end

l = Logger.new
l.start
sleep(3)
l.stop

(追記:2008/02/19)
コメントでpanさんが指摘されているように、上のエントリはThread#interruptを勘違いしてます。
Therad#interruptは

  • 実行中 → スレッドをインタラプト状態にする
  • sleep or wait → InterruptedExceptionをthrow

と動作するべきで、上のように呼ばれたら常に例外投げればいいというものではありませんでした。
interrupt呼出時の動作を表にするとこんな感じですかね。(縦が状態、横が振る舞い)

実行中 sleep or wait
割込フラグをtrueに ×
InterruptedException発生 ×