Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

synchronized and selector

20 views
Skip to first unread message

Shinji KONO

unread,
Oct 4, 2008, 4:33:14 PM10/4/08
to
河野真治 @ 琉球大学情報工学です。


河野真治 @ 琉球大学情報工学です。

いきなりですが、

Collections.synchronizedMap(new HashMap<SelectableChannel,SelectableChannel>()); 
とかいう方法で、Map(Set)自体をThread safeにすると言う手があ
るらしい。なんだが、

It is imperative that the user manually synchronize on the
returned map when iterating over any of its collection views

Interator はだめなのか。やってくれたって良いと思うんだが。
どうせ、明示的なsynchronized 文がいるなら、それを持っている
Objectのmethodに synchronized を付ける方が良いと思う。

このあたりは趣味かも知れないけど、Thread safe でないオブジ
ェクトに外部からlockするよりは、自分からlockする方が、lock
を複数取る危険性がないのと、オブジェクトの状態が明示的にな
るので良い気がする。確かに、synchronized(hoge) {} の方が、concurrency
は上がるんだけど。

 class synchronized Hoge extend HashMap { }

みたいな形で書きたい気がする。その方が並列オブジェクトっぽ
い。Java は、finalとか付いているmethodが結構あって、この手
の書き方がダメで、どうしても明示的にHashMapを持ってdelegate
する形になるんだよな。使いづらいです。

もっとも、あまりlockを広げすぎると dead lockしやすくなるん
だけど。ABCL/1で now 型ばかり使うような感じか。futureがある
と楽なんですが、java.util.concurrentのは、ちょっと構文的に
も実装的にも重すぎる。

  ────────────────────────────────

selector.select() の戻り値が、どうも信用できない。selector.
selectedKeys() で取って来ると取れるんだけど、0を返している
時があるみたいです。そもそも、

 Thread A          Thread B
 selector.select();     selector.select();
 selector.selectedKeys(); selector.selectedKeys();

と二つに分けて取っているあたりが、thread safeじゃないし。ま
ぁ、一つのselectorを二つのthread使うなってことだよな。Document
には、Selectorはsafeで、SelectedKeyは違うみたいなことが書い
てあるが...

Selectors are themselves safe for use by multiple concurrent
threads; their key sets, however, are not.

select() した後、selectedKeys(),it.remove() されると、それ
をresetするみたいな動作になっているっぽい。for(SelectedKeys
key:selector.selectedKeys()) が動かない理由も、それかな。

  ────────────────────────────────

そういえば、ググっている途中で見つけたんだが、
http://www.javareading.com/bof/network2.html
4.5.3 Selectorクラス
■なぜチャネルにセレクタを登録するのか?
 --> 逆の「セレクタにチャネルを登録する」のほうが自然なのに...
   --> なぜこのような設計になったのか、情報求む!!

ですが、これは実装を考えると、すぐにわかります。

read() でデータがなくて待っているthread Aがchannelにwait()している
select() でreadableになるのを待っているthread Bがselectorにwait()している

に対して、write()があったら、

A 用に、read()がwait()しているchannelに notify()する
B 用に、select()がwait()しているselectorに notifyAll()する

ということをするわけなんだけど、そのためには、write()したchannel
がselectorにnotifyAll()する必要があります。つまり、channel
にselectorを登録する必要があるわけ。

channelがselectorを知らないと、寝ているselectorを起こす方法がありません。

まぁ、もちろん、「セレクタにチャネルを登録する」作業の中で、
「チャネルにセレクタを登録」してやれば良いだけなんだけど。

---
Shinji KONO @ Information Engineering, University of the Ryukyus
河野真治 @ 琉球大学工学部情報工学科

0 new messages