Java并发学习笔记(10)线程同步容器

        容器的遍历,这是个非常费时的同步,如果不同步可能会发出异常,因为你在检查后的第一时间不是输出这个值,而是由其他线程在你的容器内移除最后一个元素,而你正在为输出取得这个元素时就回得到一个异常.但是把整个遍历容器加锁后.其他增删改操作将在很长一段时间内无法进行,这严重影响了其他操作使其他操作无响应. 简单的解决就是复制容器只在取得容器的部分加上同步.这样虽然开销大于以前,但是可以抽出cpu时间交给其他操作.减少了其他操作的等待时间.

JDK的同步容器

(1)Vector,HashTbale或者使用Collections.synchronizedXxx工厂方法创建创建容器的同步包装类

(2)像ArrayList这样的不同步,也不要使用容器的toString方法,这也隐式的使用了遍历.如果使用同步容器会出现2的情况.不使用安全容器调用toString将会可能产生异常.

(3)在jdk5的时候添加了Queue和BlockingQueue线程安全容器类,BlockingQueue是在Queue上加入了可阻塞插入和获取操作

(4)Jdk6加入ConcurrentSkipListMap和ConcurrentSkipListSet是SortedMap和SortedSet的代替品.PS补充:sortedMap/set中未在构造器内设置Comparator比较器则默认使用的是放入顺序.

(5)ConcurrentHashMap:

a)  使用的是分离锁

b)  不会发出ConcurrentModificationException,也就是说 在迭代时修改容器数据时不会出异常.也就是说在迭代的时候不用进行同步

c)  ConcurrentHashMap:返回的迭代器是"弱一致性"的.

d)  ConcurrentHashMap的putIfAbsent是把"检查再执行"给原子化了.

e)  ConcurrentHashMap的弱项是size和isEmpty方法size返回的可能是估算值不是十分准确的.但是对get set containsKey remove 方法加强了.所以ConcurrentHashMap在一般操作中可以完全取代Hashtable,synchronizedMap等其他同步的map.只有当程序需要独占访问加锁时,ConcurrentHashMap才不能胜任.(因为使用的是分离锁)

(6)CopyOnWriteArrayList/Set

a)  在多线程程序中代替List和Set,避免在迭代期间对容器的加锁和复制.

b)  典型的"写入时复制",在每次改变内部数组时都会复制基础数组.

c)  因为每次改变都需要复制数组,开销是很大的,所以使用这种容器在写入巨大的情况下不推荐使用.

(7)阻塞队列 BlockingQueue

a)  BlockingQueue的take和put提供阻塞服务

b)  BlockingQueue也提供容器的普通方法,可以使程序员灵活运用

c)  LinkedBlockingQueue和ArrayBlockingQueue是FIFO列队.与LinkedList和ArrayList类似,PriorityBlockingQueue是优先级队列(内的元素需要实现comparable)还有SynchronousQueue,这个BlockingQueue是最特殊的,这个没有任何内部容量,甚至连一个队列的容量都没有。不能在同步队列上进行 peek,因为仅在试图要移除元素时,该元素才存在;除非另一个线程试图移除某个元素,否则也不能(使用任何方法)插入元素;也不能迭代队列,因为其中没有元素可用于迭代。队列的 是尝试添加到队列中的首个已排队插入线程的元素;如果没有这样的已排队线程,则没有可用于移除的元素并且 poll() 将会返回 null。对于其他Collection 方法(例如 contains),SynchronousQueue 作为一个空 collection。此队列不允许 null 元素。

(8)Dqueue,BlockingDueue

a)  这两个容器分别扩展了Queue和BlockingQueue,他们的实现是ArrayDeque和LinkedBlockingDeque.是双端队列.


你可能感兴趣的:(java,jdk,多线程,vector,list,null)