内容目录
4.3.4并发性
选择器对象是线程安全的,但它们包含的键集合不是。通过keys()
和selectKeys()
返回的键的集合是Selector
对象内部的私有的Set对象集合的直接引用。这些集合可能在任意时间被改变。已注册的键的集合是只读的。如果您试图修改它,那么您得到的奖品将是一个java.lang.UnsupportedOperationException
,但是当您在观察它们的时候,它们可能发生了改变的话,您仍然会遇到麻烦。Iterator
对象是快速失败的(fail-fast):如果底层的Set
被改变了,它们将会抛出java.util.ConcurrentModificationException
,因此如果您期望在多个线程间共享选择器和/或键,请对此做好准备。您可以直接修改选择键,但请注意您这么做时可能会彻底破坏另一个线程的Iterator
。
如果在多个线程并发地访问一个选择器的键的集合的时候存在任何问题,您可以采取一些步骤来合理地同步访问。在执行选择操作时,选择器在Selector
对象上进行同步,然后是已注册的键的集合,最后是已选择的键的集合,按照这样的顺序。已取消的键的集合也在选择过程的的第1步和第3步之间保持同步(当与已取消的键的集合相关的通道被注销时)。
在多线程的场景中,如果您需要对任何一个键的集合进行更改,不管是直接更改还是其他操作带来的副作用,您都需要首先以相同的顺序,在同一对象上进行同步。锁的过程是非常重要的。如果竞争的线程没有以相同的顺序请求锁,就将会有死锁的潜在隐患。如果您可以确保否其他线程不会同时访问选择器,那么就不必要进行同步了。
Selector
类的close()
方法与slect()
方法的同步方式是一样的,因此也有一直阻塞的可能性。在选择过程还在进行的过程中,所有对close()
的调用都会被阻塞,直到选择过程结束,或者执行选择的线程进入睡眠。在后面的情况下,执行选择的线程将会在执行关闭的线程获得锁是立即被唤醒,并关闭选择器(参见4.3.2小节)。
0 条评论
撰写评论