[小ネタ]try-catchしないacquire(P命令)
ちょっとポエムかもしれないです
排他制御については解説しませんので別で調べてください。
Javaの排他制御の一つにSemaphoreがある。
try-catchしたくないよね
私があまりThrowするコードに慣れていないかもしれないが、セマフォはP命令でリソースが確保できない場合、待機すればいいだけなのに、Javaのjava.util.concurrent.Semaphore.acquire()
はpermitが一定数出ない場合、InturruptedException
を投げるので、クリティカルセクションをtry-catchでラップする必要がある。待機のみで例外を投げられるとただ実行するだけでターミナルに例外のメッセージが出される。
自分は制御的なコードは認知負荷が高いキャラビルド(書き慣れていない)ので、できるだけ避けたい。
acquire()
が例外をどう投げるのか
acquire()
のコードを見ると、単純にリソースが確保できない場合に例外を投げているだけである。単純な排他制御をするだけでSemaphoreを使う場合、または排他制御を学ぶ場合言語特有の事情に付き合うのは効率が悪い(気がする)。
そこで、例外を投げずに待機だけしてくれるacquire()
を探す。
acquireUninterruptibly
- 例外を投げないaquire()
JavaのDocsを見に行くと、acquire()
のすぐ下にacquireUninterruptibly
がある、こちらはacquire()
と違い例外を投げない。
try-catchはオーバーヘッドになる......?
「例外処理を使うとオーバーヘッドが大きい」というのはまぁ言われるのだが、今回単純なカウントアップをマルチスレッドで加算する処理を計測したのだが、実際のところ総実行時間においては例外処理ありのほうが速い。
回数 | 全体実行時間(例外処理なし) | スレッド平均実行時間(例外処理なし) | 全体実行時間(例外処理あり) | スレッド平均実行時間(例外処理あり) |
---|---|---|---|---|
1 | 4,306,800 ナノ秒 | 156,200 ナノ秒 | 2,864,200 ナノ秒 | 2,487,300 ナノ秒 |
2 | 3,767,100 ナノ秒 | 139,700 ナノ秒 | 1,511,400 ナノ秒 | 866,300 ナノ秒 |
3 | 2,697,500 ナノ秒 | 422,500 ナノ秒 | 1,272,500 ナノ秒 | 744,200 ナノ秒 |
4 | 2,122,600 ナノ秒 | 109,200 ナノ秒 | 1,059,000 ナノ秒 | 617,300 ナノ秒 |
5 | 1,928,600 ナノ秒 | 513,900 ナノ秒 | 1,031,800 ナノ秒 | 515,900 ナノ秒 |
6 | 3,063,200 ナノ秒 | 95,900 ナノ秒 | 1,144,000 ナノ秒 | 628,200 ナノ秒 |
7 | 3,213,200 ナノ秒 | 59,600 ナノ秒 | 1,143,000 ナノ秒 | 681,800 ナノ秒 |
8 | 1,595,300 ナノ秒 | 27,300 ナノ秒 | 752,300 ナノ秒 | 48,700 ナノ秒 |
9 | 3,154,200 ナノ秒 | 31,000 ナノ秒 | 2,237,900 ナノ秒 | 257,800 ナノ秒 |
10 | 5,446,900 ナノ秒 | 30,100 ナノ秒 | 796,400 ナノ秒 | 23,600 ナノ秒 |
ぶっちゃけJavaが例外をどう処理しているかをきちんと調べていないので、勝手に最適化とかしていて早い場合があるのかも?どちらにせよtry-catchはオーバーヘッドがあるという主張をするのは慎重になりたい(というか理由がわかる方には教えて下さい)
Discussion
記事の本筋にはほぼ関係ないですが、ソースコードの参照は https://github.com/openjdk/jdk の方が信頼性が高くて良いと思います。(公式なので。これもミラーですが。)