synchronized でハマッた〜

Java の synchronized はメソッドに指定するだけではなく、ブロックにも指定出来るらしい。

こんな感じ

synchronized (<object>) {
  // ロック中!
}

でこの、 は、ロックを取得する オブジェクト(参照型) を指定するんだけど、
Groovy の場合、値型 を渡してもコンパイルが通って実行出来てしまう!(多分、Boxing してるのかな)
んで、スレッドセーフなつもりのコードが実は違ったというオチ。
普段 Java 書かないから、気付かなかった。

class Hoge { 
  static int a
  void hoge1() { 
    synchronized (a) // int なのに、synchronized に渡せる! { 
      a++
    }
  }
}

Thread.start { 
  def h = new Hoge()
  (1..100000).each { h.hoge1() }
  println "end1"
}
Thread.start { 
  def h = new Hoge()
  (1..100000).each { h.hoge1() }
  println "end2"
}

Thread.sleep(1000)
println Hoge.a // あれ 200000 にならない時がある?

あと、メソッドに synchronized を指定した場合、static メソッドじゃない場合は、そのインスタンスがロック対象になるんだね〜、ちゃんと理解してなかったよ。

スレッドセーフではないはず。

class Hoge { 
  static int a
  synchronized void hoge1() { 
      a++
  }
}

スレッドセーフのはず。

class Hoge { 
  static int a
  synchronized static void hoge1() { 
      a++
  }
}