java核心技术 (卷I)[集合|并发] 精华版

10 篇文章 1 订阅

 

java核心技术系列

java核心技术(卷I)[概述|结构|对象|继承] 精华版

java核心技术(卷I)[接口|lambda|内部类|异常|泛型] 精华版

java核心技术(卷I)[集合|并发] 精化版

java核心技术 卷I
._ 集合
. ._ 集合框架
. . ._ 接口与实现分离
. . . . public interface Queue<E>
. . . . {
. . . .   void add(E element);
. . . .   E remove();
. . . .   int size();
. . . . }
. . . . . public class LInkedListQueue<E> implements Queue<E>
. . . . . {
. . . . .   private Link head;
. . . . .   private Link tail;
. . . . .   LinkedListQueue() {...}
. . . . .   public void add(E element) {...}
. . . . .   public E remove() {...}
. . . . .   public int size() {...}
. . . . . }
. . ._ 迭代器
. . . . public interface Iterator<E>
. . . . {
. . . .   E next();
. . . .   boolean hasNext();
. . . .   void remove();
. . . .   default void forEachRemaining(Consumer<? super E> action);
. . . . }
. . . . 1.需要在调用next前调用hasNext
. . . . 2.java8中可以不用写循环,可以调用forEachRemaining并提供一个lambda表达式
. . . . iterator.forEachRemaining(element->do something)
. . . . 3.可以将迭代器理解为两个元素之间,当调用next是,迭代器就越过下一个元素,并返回刚刚越过的那个元素的引用。
. . . . 4.Interator接口的remove方法将会删除上一次调用next方法时返回的元素。
. . . . 5.如果想要删除指定位置上的元素,仍然需要越过这个元素,next方法和remove方法有相互依赖性,如果调用remove之前没有调用next是不合法的。
. . ._ 实用方法
. . . ._ Collection接口
. . . . ._ int size()
. . . . ._ boolean isEmpty()
. . . . ._ boolean constans(Object obj)
. . . . ._ boolean constansAll(Collection<?> other)
. . . . ._ boolean add(Object element)
. . . . ._ boolean addAll(Collection<? extends E> other)
. . . . ._ default boolean removeIf(Predicate<? super E> filter)
. . . . ._ void clear()
. . . . . boolean retainAll(Collection<?> other)
. . . . . 从集合中删除与other集合中不同的元素
. . . . ._ Object[] toArray()
. . . . ._ <T> T[] toArray(T[] arrayToFill)
. . ._ 接口
. . . ._ 
. . . ._ 集合中有两个基本的接口Collection和Map
. . . ._ 有两种有序的集合,其性能开销有很大差异,数组支持有序集合可以快速随机访问,链表尽管也是有序的,但是随机访问很慢。
. . . ._ RadomAccess是一个标记接口,测试一个特定的集合是否支持高校的随机访问
. . ._ 具体集合
. . . ._ 
. . . ._ LinkedList
. . . . ._ 数组和数组列表都有一个很大的缺陷,就是从数组中间位置删除一个元素要付出很大的代价,原因是数组中处于被删除元素之后的所有元素都要向数组的前端移动,链表解决了这个问题
. . . . ._ add方法在迭代器之前添加一个新对象,add方法只依赖于迭代器的位置,而remove方法依赖于迭代器的状态。在调用next之后,remove方法删除迭代器左侧的元素,调用previous之后,remove方法删除迭代器右侧的元素。
. . . . ._ 如果在某个迭代器修改集合时,另一个迭代器对其进行遍历,一定会出现混乱的状况,链表迭代器能够检测到这种修改,如果迭代器发现它的集合被另一个迭代器修改了,或者被该集合自身的方法修改了,就会抛出一个ConcurrentModificationException异常。
. . . . ._ 为了避免发生并发修改异常,请遵循下述简单规则:可以根据需要给容器附加许多的迭代器,但是这些迭代器只能读取列表。另外,再单独附加一个既能读又能写的迭代器
. . . . ._ 对于并发修改列表的检测有一个奇怪的例外,链表只负责跟踪对列表结构性修改,例如,添加元素,删除元素,set方法不被视为结构性修改。
. . . . ._ 可以使用ListIterator类从前后两个方向遍历链表中的元素,并可以添加、删除元素。
. . . . ._ 链表不支持快速地随机访问,每次查找一个元素都要从链表的头部重新开始搜索,LinkedList对象根本不做任何缓存位置信息的操作
. . . . ._ get方法做了微小的变化,如果索引大于size()/2就从尾端开始搜索
. . . . ._ nextIndex返回下次调用next时返回元素的整数索引previousIndex返回下次调用previous时返回元素的整数索引
. . . . ._ list.listIterator(n)返回一个迭代器,这个迭代器指向索引为n的元素前面的位置,只是获得这个迭代器的效率比较低
. . . . ._ 使用链表的唯一理由是尽可能地减少在列表中间插入或删除元素所付出的代价
. . . . ._ api
. . . . . ._ List<E>
. . . . . . ._ ListIterator<E> listIterator
. . . . . . ._ ListIterator<E> listIterator(int index)
. . . . . . ._ void add(int i, E element)
. . . . . . ._ void addAll(int i, Collection<? extends E> elements)
. . . . . . ._ E remove(int i)
. . . . . . ._ E get(int i)
. . . . . . ._ E set(int i, E element)
. . . . . . ._ int indexOf(Object element)
. . . . . . ._ int lastIndexOf(Object element)
. . . . . ._ ListIterator<E>
. . . . . . ._ void add(E element)
. . . . . . ._ void set(E newElement)
. . . . . . ._ boolean hasPrevious()
. . . . . . ._ E previous()
. . . . . . ._ int nextIndex()
. . . . . . ._ int previousIndex()
. . . . . ._ LinkedList<E>
. . . . . . ._ LinkedList()
. . . . . . ._ LinkedList(Collection<? extends E> element)
. . . . . . ._ void addFirst(E element)
. . . . . . ._ void addLast(E element)
. . . . . . ._ E getFirst()
. . . . . . ._ E getLast()
. . . . . . ._ E removeFirst()
. . . . . . ._ E removeLast()
. . . ._ ArrayList
. . . . ._ 有两种访问元素的协议,一种是用迭代器,另一种是用get和set方法随机地访问每个元素
. . . . ._ Vector类的所有的方法都是同步的,可以由两个线程安全地访问一个Vector对象,但是如果一个线程访问Vector,代码要在同步操作上耗费大量的时间
. . . ._ 散列集
. . . . ._ 散列码
. . . . . ._ 散列码要能够快速地计算出来,并且这个计算只与要散列的对象状态有关,与散列表中的其他对象无关
. . . . ._ 散列表用链表数组实现,每个列表被称为桶,要想查找表中对象的位置,就要先计算它的散列码,然后与桶的总数取余,所得到的结果就是保存这个元素的同的索引
. . . . ._ 桶满时会从链表变为平衡二叉树,如果选择的散列函数不当,会产生很多冲突,或者如果有恶意代码视图在散列表中填充多个有相同散列码的值,这样就能提高性能
. . . . ._ 通常将桶数设置为预计元素个数的75%~150%,但最好将桶数设置为一个素数,以防键的聚集,标准类库使用的是2的幂,默认为16
. . . . ._ 如果按列表太满,就需要再散列,创建一个桶数更多的表,并将所有元素插入到这个新表中,然后丢弃原来的表,装填因子决定何时对散列表进行再散列,默认为0.75
. . . . ._ 散列集迭代器将依次访问所有的桶,由于散列将元素分散在表的各个位置上,所以访问它们的顺序几乎是随机的,只有不关心集合中元素的顺序时才应该使用HashSet
. . . . ._ api
. . . . . ._ HashSet<E>
. . . . . . ._ HashSet()
. . . . . . ._ HashSet(Collection<? extends E> element)
. . . . . . ._ HashSet(int initialCapacity)
. . . . . . ._ HashSet(int initialCapacity, float loadFactor)
. . . ._ 树
. . . . ._ 树集是一个有序集合,可以以任意顺序将元素插入到集合中
. . . . ._ 排序使用树结构完成的,当前使用的是红黑树
. . . . ._ 将一个元素添加到树中比添加到散列表中慢,但是与检查数组或链表中的重复元素相比还是快很多
. . . . ._ 要使用树集,必须能够比较元素,这些元素必须实现Comparale接口或者构造集时必须提供一个Comparator
. . . . ._ TreeSet类实现了NavigableSet接口,该接口增加了几个便于定位元素以及反向遍历的方法
. . . . ._ api
. . . . . ._ TreeSet<E>
. . . . . . ._ TreeSet()
. . . . . . ._ TreeSet(Comparator<? super E> comparator)
. . . . . . ._ TreeSet(Collection<? extends E> elements)
. . . . . . ._ TreeSet(SourtedSet<E> s)
. . . . . ._ SortedSet<E>
. . . . . . ._ Comparator<? super E> comparator()
. . . . . . ._ E first()
. . . . . . ._ E last()
. . . . . ._ NavigableSet<E>
. . . . . . ._ E higher(E value)
. . . . . . ._ E lower(E value)
. . . . . . ._ E ceiling(E value)
. . . . . . ._ E floor(E value)
. . . . . . ._ E pollFirst()
. . . . . . ._ E pollLast()
. . . . . . ._ Iterator<E> descendingIterator()
. . . ._ 队列
. . . . ._ 双端队列
. . . . . ._ 可以有效地从头部和尾部同时添加或删除元素,不支持在队列中间添加元素
. . . . . ._ api
. . . . . . ._ Queue<E>
. . . . . . . ._ boolean add(E element)
. . . . . . . . boolean offer(E element)
. . . . . . . . 将给定元素添加到双端队列的尾部,如果队列满了,则返回false
. . . . . . . ._ E remove()
. . . . . . . ._ E poll() 如果队列不为空,删除并返回头部的元素
. . . . . . . ._ E element()
. . . . . . . ._ E peek() 如果队列不为空,返回头部元素,但不删除
. . . . . . ._ Deque<E>
. . . . . . . ._ void addFirst(E element)
. . . . . . . ._ void addLast(E element)
. . . . . . . ._ boolean offerFirst(E element)
. . . . . . . ._ boolean offerLast(E element)
. . . . . . . ._ E removeFirst()
. . . . . . . ._ E removeLast()
. . . . . . . ._ E pollFirst()
. . . . . . . ._ E pollLast()
. . . . . . . ._ E getFirst()
. . . . . . . ._ E getLast()
. . . . . . . ._ E peekFirst()
. . . . . . . ._ E peekLast()
. . . . . . ._ ArrayDeque<E>
. . . . . . . ._ ArrayDeque()
. . . . . . . ._ ArrayDeque(int initialCapacity)
. . . . ._ 优先级队列
. . . . . ._ 无论何时调用remove方法,总是删除优先级最小的元素
. . . . . ._ 优先级队列使用了一个优雅而高效的数据结构,称为堆,堆是一个可以自我调整的二叉树,对树执行添加和删除操作,可以让最小的元素移动到根,而不必花费时间对元素进行排序
. . . . . ._ 与TreeSet一样,一个优先级队列既可以保存实现了Comparable接口的类对象,也可以保存在构造其中提供的Comparator对象
. . . . . ._ 优先级队列典型的示例是任务调度,每次调度都选择优先级最高的任务
. . . . . ._ api
. . . . . . ._ PriorityQueue
. . . . . . . ._ PriorityQueue()
. . . . . . . ._ PriorityQueue(int initialCapacity)
. . . . . . . ._ PriorityQueue(int initialCapacity, Comparator<? super E> c)
. . . ._ 映射
. . . . ._ 基本映射
. . . . . ._ Map<K,V>
. . . . . . ._ V get(Object key)
. . . . . . ._ default V getOrDefault(Object key, V defaultValue)
. . . . . . ._ V put(K key, V value)
. . . . . . ._ void putAll(Map<? extends K, ? extends V> entries)
. . . . . . ._ boolean containsKey(Object key)
. . . . . . ._ boolean constainsValue(Object value)
. . . . . . ._ default void forEach(BiConsumer<? super K, ? super V> action)
. . . . . ._ HashMap
. . . . . . ._ 对键进行散列
. . . . . . ._ HashMap()
. . . . . . ._ HashMap(int initialCapacity)
. . . . . . ._ HashMap(int initialCapacity, float loadFactor)
. . . . . ._ TreeMap
. . . . . . ._ 用键的整体顺序对元素进行排序
. . . . . . ._ TreeMap()
. . . . . . ._ TreeMap(Comparator<? super K> c)
. . . . . . ._ TreeMap(Map<? extends K, ? extends V> entries)
. . . . . . ._ TreeMap<SortedMap<? extends K, ? extends V> entires>
. . . . . ._ SortedMap<K,V>
. . . . . . ._ Comparator<? super K> comparator()
. . . . . . ._ K firstKey()
. . . . . . ._ K lastKey()
. . . . ._ 更新映射项
. . . . . ._ putIfAbsent() 只有当键原先存在时才会放入一个值
. . . . . ._ api
. . . . . . . default V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)
. . . . . . . 如果key与一个非null值v关联,将函数应用到v和value,将key与结果关联,或者如果结果为null,则删除这个键。否则,将key与value关联,返回get(key)
. . . . . . . default V compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
. . . . . . . 将函数应用到key和get(key),将key与结果关联,或者如果结果为null,则删除这个键,返回get(key)
. . . . . . . default V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
. . . . . . . 如果一个key与一个非null值v关联,将函数应用到key和v,将key与结果关联,或者如果结果为null,则删除这个键。返回get(key)
. . . . . . . default V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)
. . . . . . . 将函数应用到key,除非key与一个非null值关联,将key与结果关联,或者如果结果为null,则删除这个键,返回get(key)
. . . . . . . default void replaceAll(BiFunction<? super K,? super V, ? extends V> function)
. . . . . . . 在所有映射项上应用函数,将键与非null结果关联,对于null结果,则将相应的键删除
. . . . ._ 映射视图
. . . . . ._ 键集 Set<K> keySet()
. . . . . . ._ 不能向键集视图增加元素
. . . . . ._ 值集合 Collection<V> values()
. . . . . ._ Set<Map.Entry<K,V>> entrySet()
. . . . . ._ api
. . . . . . ._ Map<K,V>
. . . . . . . ._ Set<Map.Entry<K,V>> entrySet()
. . . . . . . ._ Set<K> keySet()
. . . . . . . ._ Collention<V> values()
. . . . . . ._ Map.Entry<K,V>
. . . . . . . ._ K getKey()
. . . . . . . ._ V getValue()
. . . . . . . ._ V setValue(V newValue)
. . . . ._ 弱散列映射
. . . . . ._ WeakHashMap:当对键的唯一引用来自散列条目时,这一数据结构将与垃圾回收器协同工作一起删除键/值对
. . . . . 连接散列集
. . . . . 与映射
. . . . . ._ LinkedHashSet
. . . . . ._ LinkedHashMap
. . . . . . ._ 链接散列映射将用访问顺序,而不是插入顺序,对映射条目进行迭代,每次调用get或put,受到影响的条目将从当前位置删除,并放到条目链表的尾部
. . . . . . ._ 访问顺序对于实现高速缓存的“最近最少使用”原则十分重要
. . . . . 枚举集
. . . . . 与映射
. . . . . ._ EnumSet是一个枚举类型元素集的高校实现,内部用位序列实现
. . . . . ._ EnumMap是一个键类型为枚举类型的映射,可以直接且高效用一个值数组实现
. . . . . 标识
. . . . . 散列映射
. . . . . ._ IdentityHashMap有特殊的作用,键的散列值不是用hashCode函数计算的,而是用System.identityHashCode方法计算的,在对两个对象进行比较时,IdentityHashMap使用==,而不是使用equals
. . . . . ._ api
. . . . . . ._ WeakHashMap<K,V>
. . . . . . . ._ WeakHashMap()
. . . . . . . ._ WeakHashMap(int initialCapacity, float loadFactor)
. . . . . . . ._ WeakHashMap(int initialCapacity, float loadFactor)
. . . . . . ._ LinkedHashSet<E>
. . . . . . . ._ LinkedHashSet()
. . . . . . . ._ LinkedHashSet(int initialCapacity)
. . . . . . . ._ LinkedHashSet(int initialCapacity, float loadFactor)
. . . . . . ._ LinkHashMap<K,V>
. . . . . . . ._ LinkedHashMap()
. . . . . . . ._ LinkedHashMap(int initialCapacity)
. . . . . . . ._ LinkedHashMap(int initialCapacity, float loadFactor)
. . . . . . . ._ LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)
. . . . . . . ._ protected boolean removeEldestEntry(Map.Entry<K,V> eldest)
. . . . . . ._ EnumSet<E extends Enum<E>>
. . . . . . . ._ static <E extends Enum<E>> EnumSet<E> allOf(Class<E> enumType)
. . . . . . . ._ static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> enumType)
. . . . . . . ._ static <E extends Enum<E>> EnumSet<E> range(E from, E to)
. . . . . . . ._ static <E extends Enum<E>> EnumSet<E> of(E value)
. . . . . . . ._ static <E extends Enum<E>> EnumSet<E> of(E value, E ... values)
. . . . . . ._ EnumMap<K extends Enum<K>, V>
. . . . . . . ._ EnumMap(Class<K> keyType)
. . . . . . ._ IdentityHashMap<K,V>
. . . . . . . ._ IdentityHashMap()
. . . . . . . ._ IdentityHashMap(int expectedMaxSize)
. . . . . . ._ System
. . . . . . . ._ static int identityHashCode(Object obj)
. ._ 视图与包装器
. . ._ 通过使用视图可以获得其他的实现了Collection接口和Map接口的对象:keySet方法返回一个实现Set接口的类对象,这个类方法对原映射进行操作,这种集合叫做视图
. . . 轻量级集
. . . 合包装器
. . . . Card[] cardDeck = new Card[52];
. . . . ...
. . . . List<Card> cardList = Arrays.asList(cardDeck);
. . . . 返回的对象不是ArrayList,是一个视图对象,带有访问底层数组的get和set方法。改变数组大小的所有方法都会抛出一个UnsupportedOperationException异常
. . . ._ Collections.nCopies(n, anObject) 将返回一个实现了List接口的不可修改的对象
. . . ._ Collections.singleton(anObject) 将返回一个视图对象,这个对象实现了Set接口,返回的对象实现了一个不可修改的单元素集,而不需要付出建立数据结构的开销
. . . ._ Collections.emptySet() 返回空集
. . ._ 子范围
. . . ._ staff.subList(10, 20)  第一个包含,第二个不包含
. . . ._ 可以将任何操作应用与子范围,可以删除整个子范围
. . . ._ SortedSet
. . . . ._ SortedSet<E> subSet(E from, E to)
. . . . ._ SortedSet<E> headSet(E to)
. . . . ._ SortedSet<E> tailSet(E from)
. . . ._ SortedMap<K,V>
. . . . ._ SortedMap<K,V> subMap(K from, K to)
. . . . ._ SortedMap<K,V> headMap(K to)
. . . . ._ SortedMap<K,V> tailMap(K from)
. . . ._ NavigableSet<E>
. . . . ._ NavigableSet<E> subSet(E from , boolean fromInclusive, E to, boolean toInclusive)
. . . . ._ NavigableSet<E> headSet( E to, boolean toInclusive)
. . . . ._ NavigableSet<E> subSet(E from , boolean fromInclusive)
. . . 不可修
. . . 改视图
. . . ._ Collections还有几个方法,用于产生集合的不可修改视图,这些视图对现有集合增加了一个运行时检查,如果发现视图对集合进行修改,就会抛出一个异常。
. . . . Collections.unmodifiableCollection
. . . . Collections.unmodifiableList
. . . . Collections.unmodifiableSet
. . . . Collections.unmodifiableSortedSet
. . . . Collections.unmodifiableNavigableSet
. . . . Collections.unmodifiableMap
. . . . Collections.unmodifiableSortedMap
. . . . Collections.unmodifiableNavigableMap
. . ._ 同步视图
. . . . 类库设计者使用视图机制来确保常规集合的线程安全,而不是实现线程安全的集合类,例如Collections类的静态synchronizedMap方法可以将任意一个映射转换成为具有同步访问方法的map
. . . . Map<String, Employee> map = Collections.syschronizedMap(new HashMap<String, Employee>)
. . . . 现在,就可以由多线程访问map对象了。
. . ._ 受查视图
. . . . List<String> safeStrings = Collections.checkedList(strings, String.class)
. . . . 视图的add方法将检测插入的对象是否属于给定的类
. . ._ api
. . . ._ Collections
. . . . ._ static <E> Collection unmodifiableCollection(Collection<E > c)
. . . . ._ static <E> Collection unmodifiableLIst(List<E > c)
. . . . ._ static <E> Collection unmodifiableSet(Set<E > c)
. . . . ._ static <E> Collection unmodifiableSortedSet(SortedSet<E > c)
. . . . ._ static <E> Collection unmodifiableNavigableSet(NavigableSet<E > c)
. . . . ._ static <K,V> Collection unmodifiableMap(Map<K,V> c)
. . . . ._ static <K,V> Collection unmodifiableSortedMap(SortedMap<K,V> c)
. . . . ._ static <K,V> Collection unmodifiableNavigableMap(NavigableMap<K,V> c)
. . . . ._ static <E> Collection<E> synchronizedCollection(Collection<E> c)
. . . . ._ static <E> LIst<E> synchronizedList(List<E> c)
. . . . ._ static <E> Set<E> synchronizedSet(Set<E> c)
. . . . ._ static <E> SortedSet<E> synchronizedSortedSet(SortedSet<E> c)
. . . . ._ static <E> NavigableSet<E> synchronizedNavigableSet(NavigableSet<E> c)
. . . . ._ static <K,V> Map<E> synchronizedMap(Map<K,V> c)
. . . . ._ static <K,V> SortedMap<E> synchronizedSortedMap(SortedMap<K,V> c)
. . . . ._ static <K,V> NavigableMap<E> synchronizedNavigableMap(NavigableMap<K,V> c)
. . . . ._ static <E> Collection checkedCollection(Collection<E> c, Class<E> elementType)
. . . . ._ static <E> List checkedList(List<E> c, Class<E> elementType)
. . . . ._ static <E> Set checkedSet(Set<E> c, Class<E> elementType)
. . . . ._ static <E> SortedSet checkedSortedSet(SortedSet<E> c, Class<E> elementType)
. . . . ._ static <E> NavigableSet checkedNavigableSet(NavigableSet<E> c, Class<E> elementType)
. . . . ._ static <K,V> Map checkedMap(Map<K,V> c, Class<E> elementType)
. . . . ._ static <K,V> SortedMap checkedSortedMap(SortedMap<K,V> c, Class<E> elementType)
. . . . ._ static <K,V> NavigableMap checkedNavigableMap(NavigableMap<K,V> c, Class<E> elementType)
. . . . ._ static <E> Queue<E> checkedQueue(Queue<E> queue, Class<E> elementType)
. . . . ._ static <E> List<E> nCopies(int n, E value)
. . . . ._ static <E> Set<E> singleton(E value)
. . . . ._ static <E> List<E> singletonList(E value)
. . . . ._ static <K,V> Map<K,V> singletonMap(K key, V value)
. . . . ._ static <E> List<E> emptyList()
. . . . ._ static <E> Set<T> emptySet()
. . . . ._ static <E> SortedSet<E> emptySortedSet()
. . . . ._ static NavigableSet(E) emptyNavigableSet()
. . . . ._ static <K,V> Map<K,V> emptyMap()
. . . . ._ static <K,V> SortedMap<K,V> emptySortedMap()
. . . . ._ static <K,V> NavigableMap<K,V> emptyNavigableMap()
. . . . ._ static <T> Enumeration<T> emptyEnumeration()
. . . . ._ static <T> Iterator<T> emptyIterator()
. . . . ._ static <T> ListIterator<T> emptyListIterator()
. . . ._ Arrays
. . . . ._ static <E> List<E> asList(E ... array)
. . . ._ List<E>
. . . . ._ List<E> subList(int firstIncluded, int firstExcluded)
. . . ._ SortedSet<E>
. . . . ._ SortedSet<E> subSet(E firstIncluded, E firstExcluded)
. . . . ._ SortedSet<E> headSet(E firstExcluded)
. . . . ._ SortedSet<E> tailSet(E firstInclude)
. . . ._ SortedMap<K,V>
. . . . ._ SortedMap<K,V> subMap(K from, K to)
. . . . ._ SortedMap<K,V> headMap(K to)
. . . . ._ SortedMap<K,V> tailMap(K from)
. . . ._ NavigableSet<E>
. . . . ._ NavigableSet<E> subSet(E from , boolean fromInclusive, E to, boolean toInclusive)
. . . . ._ NavigableSet<E> headSet( E to, boolean toInclusive)
. . . . ._ NavigableSet<E> subSet(E from , boolean fromInclusive)
. . . ._ NavigableMap<K,V>
. . . . ._ NavigableMap<K,V> subMap(K from, boolean fromIncluded, K to, boolean toIncluded)
. . . . ._ NavigableMap<K,V> headMap(K to, boolean toIncluded)
. . . . ._ NavigableMap<K,V> tailMap(K from,  boolean fromIncluded)
. ._ 算法
. . ._ 泛型集合接口有一个很大的好处,就是算法秩序实现一次
. . . 排序
. . . 混排
. . . . Collections.sort()
. . . . 升序排序,元素需实现Comparable接口
. . . . 实现:直接将所有元素转入一个数组,对数组进行拍讯,然后,再将排序后的序列复制回列表
. . . . Collections.reverseOrder()
. . . . 降序排序,元素同样需实现Comparable接口
. . . ._ 集合类库中使用的排序算法比快速排序要慢一些,快速排序是通用排序算法的传统选择,但是归并排序有一个主要的有点:稳定,即不需要交换相同的元素。
. . . ._ Collections.shuffle() 与排序相反,随机地混排列表中的元素,如果列表没有实现RandomAccess接口,shuffle方法将元素复制到数组中,然后打乱数组元素的顺序,最后再将打乱顺序后的元素复制回列表
. . . ._ api
. . . . ._ Collections
. . . . . ._ static <T extends Comparable<? super T>> void sort(List<T> elements)
. . . . . ._ static void shuffle(List<?> element)
. . . . . . static void shuffle(List<?> element, Random r)
. . . . . . 这个算法的复杂度是O(n a(n)),n是列表的长度,a(n)是访问元素的平均时间
. . . . ._ List<E>
. . . . . ._ default void sort(Comparator<? super T> comparator)
. . . . ._ Comparator<T>
. . . . . ._ satic <T extends Comparable<? super  T>> Comparator<T> reverseOrder()
. . . . . ._ default Comparator<T> reversed()
. . . 二分
. . . 查找
. . . . Collection.binarySearch()
. . . . 集合必须是排好序的
. . . ._ 只有采用随机访问的方式,二分查找才有意义,如果给binarySearch提供一个链表,则将自动地变为线性查找
. . . ._ api
. . . . ._ Collections
. . . . . ._ static <T extends Comparable<? super T>> int binarySearch(List<T> element, T key)
. . . . . ._ static <T> binarySearch(List<T> element, T key, Comparator<? super T> c)
. . . 简单
. . . 算法
. . . ._ Collections
. . . . . static <T extends Comparable<? super T>> T min(Collectiion<T> elements)
. . . . . static <T extends Comparable<? super T>> T max(Collection<T> elements) 
. . . . . static <T> min(Collection<T> elements, Comparator<? super T>  c)
. . . . . static <T> max(Collection<T> elements, Comparator<? super T>  c)
. . . . . static <T> void copy(List<? super T> to, List<T> from)
. . . . . static <T> void fill(List<? super T> l, T value)
. . . . . static <T> boolean addAll(Collection<? super T> c, T ... values)
. . . . . static <T> boolean replaceAll(List<?> l, T oldValue, T newValue)
. . . . . 用newValue取代所有值为oldValue的元素
. . . . . static int indexOfSubList(List<?> l, List<?> s)
. . . . . static int lastIndexOfSubList(List<?> l, List<?> s)
. . . . . static void swap(List<?> l, int i, int j)
. . . . . 交换给定偏移量的两个元素
. . . . . static void reverse(List<?> l)
. . . . . 逆置列表中的元素
. . . . . static void rotate(List<?> l, int d)
. . . . . 旋转列表中的元素,将索引i的条目移动到位置(i+d)%l.size()
. . . . . static int frequency(Collection<?> c, Object o)
. . . . . 返回c中与对象o相同元素的个数
. . . . . boolean disjoint(Collection<?> cl, Collection<?> c2)
. . . . . 如果两个集合没有共同元素,则返回true
. . . ._ Collection<T>
. . . . . default boolean removeIf(Predicate<? super E> filter)
. . . . . 删除所有匹配的元素
. . . ._ List<E>
. . . . . default void replaceAll(UnaryOperator<E> op)
. . . . . 对这个列表的所有元素应用这个操作
. . ._ 批操作
. . . . coll1.removeAll(coll2)
. . . . 从coll1中删除coll2中出现的所有元素
. . . . coll1.retainAll(coll2)
. . . . 从coll1中删除所有未在coll2中出现的元素
. . . . Map<String, Employee> staffMap = ...;
. . . . Set<String> terminatedIDs = ...;
. . . . staffMap.keySet().removeAll(terminatedIDs)
. . . . 由于键集是映射一个视图,所以键和相关联的员工名会自动从映射中删除
. . . 集合与
. . . 数组转换
. . . . Object[] values = staff.toArray();
. . . . toArray返回的数组是一个Object[]数组,不能改变它的类型,必须用toArray的一个变体形式,提供一个所需类型而且长度为0的数组,这样,返回的数组就会创建为相同的数组类型,如下:
. . . . String[] values = staff.toArray(new String[0]);
. . ._ 遗留的集合
. . . ._ Hashtable
. . . . ._ Hashtable与HashMap作用一样,Hashtable方法是同步的,如果对同步性或与遗留代码的兼容性没有任何要求,就应该使用HashMap,如果需要并发访问,则要使用ConcurrentHashMap。
. . . ._ 枚举
. . . . ._ 遗留集合使用Enumeratioon接口对元素进行遍历
. . . ._ 属性映射
. . . . . 属性映射Properties是一个非常特殊的映射结构
. . . . . 键与值都是字符串
. . . . . 表可以保存到一个文件中,也可以从文件中加载
. . . . . 使用一个默认的辅助表
. . . ._ 栈
. . . . ._ Stack
. . . ._ 位集
. . . . ._ BisSet类用于存放一个位序列,如果需要高效地存储位序列,就可以使用位集
. . . . ._ Eratosthenes筛子算法:查找素数实现,并不是一种查找素数的最好方法,但已成为测试编译程序性能的一种流行的基准:首先将所有的位置为“开”状态,然后,将已知素数的倍数所对应的位都置为“关”状态,经过这个操作保留下来的位对应的就是素数
. . . ._ api
. . . . ._ Enumeration<E>
. . . . . ._ boolean hasMoreElements()
. . . . . ._ E nextElement()
. . . . ._ Hashtable<K,V>
. . . . . ._ Enumeration<K> keys()
. . . . . ._ Enumeration<V> elements()
. . . . ._ Vector<E>
. . . . . ._ Enumeration<E> elements()
. . . . ._ Properties
. . . . . ._ Properties()
. . . . . ._ Properties(Properties defaults)
. . . . . ._ String getProperty(String key)
. . . . . ._ String getProperty(String key, String defaultValue)
. . . . . ._ void load(InputString in)
. . . . . ._ void store(OutputStream out, String commentString)
. . . . ._ Stack<E>
. . . . . ._ E push(E item)
. . . . . . E pop()
. . . . . . 弹出并返回栈顶的元素
. . . . . . E peek()
. . . . . . 返回栈顶元素,但不弹出
. . . . ._ BitSet
. . . . . ._ BitSet(int initialCapacity)
. . . . . ._ int length()
. . . . . ._ boolean get(int bit)
. . . . . ._ void set(int bit)
. . . . . ._ void clear(int bit)
. . . . . ._ void and(BitSet set)
. . . . . ._ void or(BitSet set)
. . . . . ._ void xor(BitSet set)
. . . . . ._ void andNot(BitSet set)
._ 并发
. ._ 线程
. . ._ Thread
. . . ._ static void sleep(long millis)
. . . ._ Thread(Runnable target)
. . . . void start()
. . . . 启动这个线程,将引发调用run方法,这个方法将立即返回,并且新线程将并发运行
. . . ._ void run()
. . . ._ 示例
. . . . . class MyThread extends Thread
. . . . . {
. . . . .   public void run()
. . . . .   {
. . . . .     task code
. . . . .   }
. . . . . }
. . ._ Runnable
. . . ._ void run()
. . . . . public interface Runnable
. . . . . {
. . . . .   void run();
. . . . . }
. . . . . Runnable r = () -> {task code};
. . . . . Thread t = new Thread(t);
. . . . . t.start();
. . 中断
. . 线程
. . ._ 终止线程的方法
. . . ._ 线程的run方法执行方法体中最后一条语句,并return
. . . ._ 出现了在方法中没有捕获的异常
. . . ._ 其他线程调用stop终止线程,已被弃用
. . . 没有可以强制线程终止的方法,然而,interrupt方法可以用来请求终止线程
. . . 当对一个线程调用interrupt方法时,线程的中断状态被置位,这是每一个线程都具有的boolean标志,每个线程都应该不时地检查这个标志,以判断线程是否被中断
. . . while (!Thread.currentThread().isInterrupted() && more work to do) 
. . . {
. . .   do more work
. . . }
. . . 如果线程被阻塞,就无法检测中断状态,这会产生InterruptedException异常,当在一个被阻塞的线程上调用interrupt方法时,阻塞调用将会被Interrupt Exception异常中断
. . ._ Interrupted方法是一个静态方法,它检测当前线程是否被中断,而且,调用interrupted方法会清除该线程的中断状态。另一方面,isInterrupted方法是一个实例方法,可用来检测是否有线程被中断,该方法不会改变中断状态。
. . 线程
. . 状态
. . . 线程的6种状态:
. . . New 新创建
. . . Runnable 可运行
. . . Blocked 被阻塞
. . . Waiting 等待
. . . Timed waiting 计时等待
. . . Terminated  被终止
. . . ._ 
. . ._ 新创建线程
. . . ._ new Thread时,线程处于new状态
. . ._ 可运行线程
. . . ._ 调用start方法,线程处于runnable状态
. . . ._ 运行的线程被中断,目的是让其他线程获得运行机会,抢占式调度系统给每一个可运行的线程一个时间片来执行任务
. . . ._ 在协作式调度设备中,一个线程只有在调用yield方法,或者被阻塞或等待时,线程才失去控制权
. . . ._ 在具有多个处理器的机器上,每一个处理器运行一个线程,可以与多个线程并行运行,如果线程的数目多于处理器的数目,调度器依然采用时间片机制。
. . . 被阻塞和
. . . 等待线程
. . . ._ 当线程处于被阻塞或等待状态时,它暂时不活动,它不运行任何代码且消耗最少的资源
. . . . 阻塞状态:
. . . . 当一个线程试图获取一个内部的对象锁,而该锁被其他线程持有
. . . ._ 等待状态:
. . . . ._ Object.wait
. . . . ._ Thread.join
. . . . ._ Lock
. . . . ._ Condition
. . . . 计时等待状态:
. . . . 调用计时等待方法
. . . . ._ Thread.sleep
. . . . ._ Object.wait
. . . . ._ Thread.join
. . . . ._ Lock.tryLock
. . . . ._ Condition.await
. . . ._ 当一个线程被阻塞或等待时,另一个线程被调度为运行状态,调度器检查它是否具有比当前运行线程更高的优先级,如果是,调度器从当前运行线程中挑选一个,剥夺其运行权,选择一个新的线程运行
. . . 被终止
. . . 的线程
. . . ._ run方法正常退出而自然死亡
. . . ._ 因为一个没有捕获的异常终止了run方法而意外死亡
. . ._ api
. . . ._ Thread
. . . . ._ void join()
. . . . ._ void join(long millis)
. . . . ._ Thread.State getState()
. . . . ._ void stop()
. . . . ._ void suspend()
. . . . ._ void resume()
. . 线程
. . 属性
. . ._ 优先级
. . . ._ 每一个线程都有一个优先级,默认情况下,一个线程继承它的父线程的优先级,可以调用setPriority方法提高或降低任何一个线程的优先级
. . . ._ api
. . . . ._ Thread
. . . . . ._ void setPriority(int newPriority)
. . . . . ._ static int MIN_PRIORITY
. . . . . ._ static int NORM_PRIORITY
. . . . . ._ static int MAX_PRIORITY
. . . . . ._ static void yield()
. . ._ 守护线程
. . . ._ t.setDaemon(true) 将线程转换为守护线程,守护线程唯一的用途就是为其他线程提供服务。当只剩下守护线程时,虚拟机就退出了。
. . . ._ 守护线程永远不去访问固有资源,如文件,数据库,因为它会在任何时候甚至在一个操作中发生中断。
. . . ._ api
. . . . ._ Thread
. . . . . ._ void setDaemon(boolean isDaemon)
. . . 未捕
. . . 获异
. . . 常处
. . . 理器
. . . ._ 线程的run方法不能抛出任何受查异常,但是非受查异常会导致线程终止,在这种情况下,线程就死亡了
. . . . 不需要任何catch子句来处理可以被传播的异常,在线程死亡之前,异常被传递到一个用于捕获异常的处理器,该处理器必须属于一个实现Thread.UncaughtExceptionHandler接口的类,这个接口只有一个方法
. . . . void uncaughtException(Thread t, Throwable e)
. . . . 为指定线程安装一个处理器
. . . . setUncaughtExceptionHandler
. . . . 为所有线程安装一个默认的处理器
. . . . setDefaultUncaughtExceptionHandler
. . . ._ 如果不安装默认处理器,默认处理器为空,如果不为独立的线程安装处理器,此时的处理器就是该线程的ThreadGroup对象
. . . . ThreadGroup类的uncaughtException方法做如下操作
. . . . 1.如果该线程组有父线程组,那么父线程组的uncaughtException方法被调用。
. . . . 2.否则,如果Thread.getDefaultExceptionHandler方法返回一个非空的处理器,则调用该处理器
. . . . 3.否则,如果Throwable是ThreadDeath的一个实例,什么都不做
. . . . 4.否则,线程的名字以及Throwable的栈轨迹被输出到System.err上
. . . ._ api
. . . . ._ Thread
. . . . . ._ static void setdDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler handler)
. . . . . ._ static Thread.UncaughtExceptinHandler getDefaultUncaughtExceptionHandler()
. . . . . ._ void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler handler)
. . . . . ._ Thread.UncaughtExceptionHandler getUncaughtExceptionHandler()
. . . . ._ Thread.UncaughtExceptionHandler
. . . . . ._ void uncaughtException(Thread t, Throwable e)
. . . . ._ ThreadGroup
. . . . . ._ void uncaughtException(Thread t, Throwable e)
. ._ 同步
. . ._ 锁对象
. . . ._ 两种机制
. . . . ._ synchronized
. . . . . ._ 提供一个锁以及相关条件
. . . . ._ ReentrantLock
. . . . . . myLock.lock();
. . . . . . try
. . . . . . {
. . . . . .   critical section
. . . . . . }
. . . . . . finally
. . . . . . {
. . . . . .   myLock.unlock();
. . . . . . }
. . . . . ._ 把解锁操作放在finally中是至关重要的
. . . . . ._ 不能把锁放在带资源的try语句中
. . . . . ._ 锁是可重入的,因为线程可以重复地获得已经持有的锁,锁保持一个持有计数来跟踪对lock方法的嵌套调用。线程在每一次调用lock都要调用unlock来释放锁。
. . . . . ._ 被一个锁保护的代码可以调用另一个使用相同锁的方法
. . . . . ._ 如果在临界区的代码结束前抛出了异常,finally子句将释放锁,但会使对象可能处于一种受损的状态
. . . . ._ api
. . . . . ._ Lock
. . . . . . ._ void lock()
. . . . . . ._ void unlock()
. . . . . ._ ReentrantLock
. . . . . . ._ ReentrantLock()
. . . . . . . RenntrantLock(boolean fair)
. . . . . . . 构建一个带有公平策略的锁,一个公平锁偏爱等待时间最长的线程,但是,这一公平的保证将大大降低性能,默认情况下,锁没有被强制为公平的。
. . . . . . . 即使使用公平锁,也无法确保线程调度器是公平的
. . . 条件
. . . 对象
. . . ._ 通常,线程进入临界区后,却发现在某一条件满足后它才能执行,要使用一个条件对象来管理那些已经获得一个锁但是却不能做有用工作的线程。
. . . ._ 条件对象也成为条件变量
. . . . 一个锁对象可以有一个或多个相关的条件对象,可以用newCondition方法获得一个条件对象
. . . . class Bank
. . . . {
. . . .   private Condition sufficientFunds;
. . . .   ...
. . . .   public Bank()
. . . .   {
. . . .     ...
. . . .     sufficientFunds = bankLock.newCondition();
. . . .   }
. . . . }
. . . . // 等待某个条件
. . . . sufficientFunds.await();
. . . . 
. . . . // 另一个线程中,条件满足时
. . . . suficientFunds.signalAll();
. . . . 当调用sufficientFunds.await(),线程被阻塞了,并放弃了锁
. . . ._ 一旦一个线程调用await方法,它进入该条件的等待集,当锁可用时,该线程不能马上解除阻塞,相反,它处于阻塞状态,直到另一个线程调用同一条件上的signalAll方法为止。
. . . ._ 注意调用signalAll不会立即激活一个等待线程,它仅仅解除等待线程的阻塞,以便这些线程可以在当前线程退出同步方法之后,通过竞争实现对对象的访问。
. . . ._ signal方法随机解除等待集中某个线程的阻塞状态
. . . ._ api
. . . . ._ Lock
. . . . . ._ Condition newCondition()
. . . . ._ Condition
. . . . . ._ void await()
. . . . . ._ void signalAll()
. . . . . ._ void signal()
. . . synchronized
. . . 关键字
. . . . 有关锁和条件的关键之处:
. . . . 1.锁用来保护代码片段,任何时刻只能有一个线程执行被保护的代码。
. . . . 2.锁可以管理试图进入被保护代码段的线程。
. . . . 3.锁可以拥有一个或多个相关的条件对象。
. . . . 4.每个条件对象管理那些已经进入被保护代码段但还不能运行的线程
. . . . java的每个对象都有一个内部锁,如果一个方法被synchronized关键字声明,那么对象的锁将保护整个方法,也就是说,要调用该方法,线程必须获得内部的对象锁。换句话说:
. . . . public synchronized void method()
. . . . {
. . . .   method body
. . . . }
. . . . 等价于
. . . . public void method()
. . . . {
. . . .   this.intrinsicLock.lock();
. . . .   try 
. . . .   {
. . . .      method body
. . . .   }
. . . .   finally { this.intrinsiccLock.unlock(); }
. . . . }
. . . ._ 内部锁对象只有一个相关条件,wait方法添加一个线程到等待集中,notifyAll/notify方法解除等待线程的阻塞状态
. . . . wait、notifyAll以及notify方法是Object类的final方法。Condition方法必须被命名为await、signalAll、signal以便不会与那些方法产生冲突
. . . . 可以理解为wait/notifyAll/notify作用在内部锁对象关联的唯一条件上,而await/signalAll/signal作用在锁的某一个条件上。
. . . ._ 将静态方法声明为synchronized也是合法的,该方法获得相关的类对象的内部锁
. . . ._ 静态方法上的synchronized获得类Class上的锁,实例方法上的synchronized获得实例对象上的锁
. . . . 内部锁和条件存在一些局限
. . . . 1.不能中断一个试图获得锁的线程
. . . . 2.试图获得锁时,不能设定超时
. . . . 3.每个锁仅有单一的条件,可能是不够的
. . . . 使用哪一种锁的建议:
. . . . 1.最好既不使用Lock/Condition也不使用synchronized关键字,在许多情况下,可以使用java.util.concurrent包中的一种机制,它会为你处理所有的加锁,如阻塞队列
. . . . 2.如果synchronized适合你的程序,请尽量使用它,这样可以减少编写代码的数量,减少出错的几率
. . . . 3.如果特别需要Lock/Condition结构提供的独有特性时,才使用Lock/Condition
. . . ._ api
. . . . ._ Object
. . . . . ._ void notifyAll()
. . . . . . void notify()
. . . . . . 随机选择一个在该对象上调用wait方法的线程,解除其阻塞状态,该方法只能在一个同步方法或同步块中调用。
. . . . . ._ void wait()
. . . . . ._ void wait(long millis)
. . . . . ._ void wait(long millis, int nanos)
. . . 同步
. . . 阻塞
. . . . 还有另外一种机制获得锁,通过进入一个同步阻塞
. . . . synchronized (obj)
. . . . {
. . . .   critical section
. . . . }
. . . . 有时会发现特殊的锁
. . . . public class Bank
. . . . {
. . . .   private double[] accounts;
. . . .   private Object lock = new Object();
. . . .   public void transfer(int from, int to, int amount) 
. . . .   {
. . . .     synchronized(lock)
. . . .     {
. . . .        accounts[from] -= amount;
. . . .        accounts[to] += amount;
. . . .     }
. . . .   }
. . . . }
. . . . 有时使用一个对象的锁来实现额外的原子操作,实际上称为客户端锁定
. . . . public void transfer(Vector<Double> accounts, int from, int to, int amount)
. . . . {
. . . .   synchronized(accounts)
. . . .   {
. . . .     accounts.set(from, accounts.get(from) - amount);
. . . .     accounts.set(to, accounts.get(to) + amount)
. . . .   }
. . . . }
. . . . Vector类是线程安全的,以上代码假定Vector类对自己的所有修改都使用内部锁,文档中没有给出这样的承诺
. . . . 客户端锁定是非常脆弱的,通常推荐使用
. . ._ 监视器
. . . ._ 锁和条件是线程同步的强大工具,但是严格地讲,它们不是面向对象的,多年来,研究人员努力寻找一种方法,可以在不需要程序员考虑如何加锁的情况下,就可以保证多线程的安全性。最成功的解决方案就是监视器。
. . . . 监视器具有如下特性:
. . . . 1.监视器是只包含私有域的类
. . . . 2.每个监视器对象有一个相关的锁
. . . . 3.使用该锁对所有的方法进行加锁。如果客户端调用obj.method(),那么obj对象的锁是在方法调用开始时自动获得,方法返回时自动释放锁。
. . . . 4.该锁可以有任意多个相关条件。
. . ._ Volatile	
. . . ._ volatile提供了一种免锁机制,编译器和虚拟机认为volatile域可能被另一个线程并发更新的
. . . ._ 警告:volatile不能提供原子性
. . ._ final变量
. . . ._ 其他线程在构造函数完成后才能看到final域
. . ._ 原子性
. . . . java.util.concurrent.atomic包中许多类使用了很高效的机器级指令来保证其他操作的原子性,如AtomicInteger
. . . . public static AtomicLong nextNumber = new AtomicLong();
. . . . long id = nextNumber.incrementAndGet();
. . . ._ 如果有大量的线程要访问相同的原子值,性能会大幅下降,因为乐观更新需要太多次重试。java8中提供了LongAdder和LongAccumulator类来解决这个问题,LongAdder包括多个变量(加数),其总和为当前值,可以有多个线程更新不同的加数,线程个数增加时会自动提供新的加数,这种方式,性能会显著提升。
. . . . LongAccumulator将上述思维推广到了任意的累加操作
. . . . LongAccumulator adder = new LongAccumulator(Long::sum, 0);
. . . . adder.accumulate(value);
. . . . 在内部,这个累加器包含变量a1,a2,...an,每个变量初始化为0元素,调用accumulate并提供value值时,其中一个变量以原子的方式更新a1 = a1 op value,get的结果是a1 op a2 op ....an,例子中是a1 + a2 + ... + an
. . . ._ DoubleAdder和DoubleAccumulate也采用了同样的方式
. . ._ 死锁
. . . ._ 这里介绍的不详细,建议参考《java编程思想》中关于死锁的介绍:死锁的四个条件以及如何打破死锁。
. . . ._ java中没有提供任何东西可以避免死锁的发生,必须仔细设计程序,确保不会发生死锁。
. . . 线程
. . . 局部
. . . 变量
. . . ._ 线程间共享变量是有风险的,为避免共享变量,使用ThreadLocal辅助类为各个线程提供各自的实例
. . . . java.util.Random类是线程安全的,但是如果多线程需要等待一个共享的随机数生成器,就会很低效。
. . . . ThreadLocalRandom类解决了这个问题,该类的current方法返回当前线程的Random类实例
. . . ._ api
. . . . ._ ThreadLocal<T>
. . . . . ._ T get()
. . . . . ._ protected initialize()
. . . . . ._ void set(T t)
. . . . . ._ void remove()
. . . . . ._ static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier)
. . . . ._ ThreadLocalRandom
. . . . . ._ static ThreadLocalRandom current()
. . . 锁测试
. . . 与超时
. . . ._ lock方法在获得锁时可能会阻塞,所以应该谨慎地申请锁
. . . ._ tryLock试图申请一个锁,如果申请成功则返回true,否则,立即返回false,线程可以做其他的事情。
. . . ._ lock方法不能被中断,如果一个线程在等待获得一个锁时被中断,中断线程在获得锁之前一直处于阻塞状态,如果出现死锁,lock方法就无法终止。
. . . ._ 如果调用带超时参数的tryLock,那么如果线程在等待期间被中断,将会抛出InterruptedException异常。此特性很有用,因允许程序打破死锁。
. . . ._ 也可以使用lockInterruptibly方法,它就相当于超时设为无线的tryLock方法
. . . ._ 如果等待的线程被中断,await方法将抛出一个nterruptedException异常,此时,如果你希望继续等待,则可调用awaitUninterruptibly方法代替await
. . . ._ api
. . . . ._ Lock
. . . . . ._ boolean tryLock()
. . . . . ._ boolean tryLock(long time, Timeout unit)
. . . . . ._ void lockInterruptibly()
. . . . ._ Condition
. . . . . ._ boolean await(long time, TimeUnit unit)
. . . . . ._ void awaitUninterruptibly()
. . ._ 读/写锁
. . . ._ java.util.concurrent.locks包定义了两个锁类,ReentrantLock和ReentrantReadWriteLock类,如果很多线程从一个数据结构读取数据而很少线程修改其中的数据的话,后者十分有用。
. . . . 使用读写锁必要的步骤:
. . . . 1)构造一个ReentrantReadWriteLock对象
. . . . private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock;
. . . . 2)抽取读锁和写锁
. . . . private Lock readLock = rwl.readLock();
. . . . private Lock writeLock = rwl.writeLock();
. . . . 3)对所有的获取方法加读锁
. . . . public double getTotalBalance()
. . . . {
. . . .   readLock.lock();
. . . .   try { . . . }
. . . .   finally { readLock.unlock(); }
. . . . }
. . . . 对所有修改方法加写锁
. . . . public void transfer( . . . )
. . . . {
. . . .   writeLock.lock();
. . . .   try { . . . }
. . . .   finally { writeLock.unlock(); }
. . . . }
. . . ._ api
. . . . ._ ReentrantReadWriteLock
. . . . . ._ Lock readLock()
. . . . . ._ Lock writeLock()
. . . 已弃用
. . . 的方法
. . . ._ stop、suspend和resume方法已经弃用。
. . . ._ stop方法天生就不安全。当线程要终止另一个线程时,无法知道什么时候调用stop是安全的,什么时候导致对象破坏。在希望停止线程的时候应该中断线程,被中断的线程会在安全的时候停止。
. . . . 经验证明suspend方法会经常导致死锁。如果syspend挂起一个持有一个锁的线程,那么,该锁在恢复之前是不可用的,如果调用suspend的线程试图获得同一个锁,那么程序死锁
. . . . 如果想安全地挂起一个线程,引入一个变量suspendRequested并在run方法的某一个安全的地方测试它,安全的地方是指该线程没有封锁其他线程需要的对象的地方。当该线程发现suspendRequested变量已经被设置,将会保持等待状态直到它获得为止。
. . 阻塞
. . 队列
. . ._ 应该尽可能远离底层结构,使用并发处理的专业人士实现的较高层次的结构要方便得多,安全得多。
. . . 对于许多线程问题,可以通过一个或多个队列以优雅且安全的方式将其形式化。
. . . 使用队列,可以安全地从一个线程向另一个线程传递数据。
. . ._ 当试图向队列添加元素而队列满,或是想从队列移出元素而队列为空的时候,阻塞队列导致线程阻塞。
. . ._ 在协调多个线程之间合作时,阻塞队列是一个很有用的工具,队列会自动平衡负载。
. . ._ 在一个多线程程序中,队列会在任何时候空或满,一定要使用offer、poll和peek取代add、remove和element以防止发生异常。
. . ._ LinkedBloackingQueue:一个双端队列实现的版本,容量是没有上限的,也可以选择指定最大容量。
. . ._ ArrayBlockingQueue:构造时需要指定容量,并且有一个可选的参数来指定是否需要公平性。如果设置的公平参数,那么等待最长时间的线程会优先得到处理,通常,公平性会降低性能,只有在确实非常需要时才使用它。
. . ._ PriorityBlockingQueue:一个带优先级的队列,而不是先进先出队列,元素按照他们的优先级顺序被移出,该队列没有容量上限,但是如果队列是空的,取元素的操作会阻塞。
. . ._ DelayQueue:实现了Delayed接口的对象,getDelay方法返回对象的残留延迟。负值表示延迟已结束,元素只有在延迟用完的情况下才能从队列中移除,还必须实现compartTo方法,DelayQueue使用该方法对元素进行排序
. . . tranferQueue接口:允许生产者线程等待,直到消费者准备就绪可以接收一个元素。如果生产者调用q.transfer(item),这个调用会阻塞,直到另一个线程将元素删除。
. . . LinkedBlockingQueue类实现了这个接口。
. . ._ api
. . . ._ ArrayBlockingQueue<E>
. . . . ._ ArrayBlockingQueue(int capacity)
. . . . ._ ArrayBlockingQueue(int capacity, boolean fair)
. . . ._ LinkedBlockingQueue<E>
. . . . ._ LinkedBlockingQueue()
. . . . ._ LinkedBlockingQueue(int capacity)
. . . ._ DelayQueue<E extends Delayed>
. . . . ._ DelayQueue()
. . . ._ Delayed
. . . . ._ long getDelay(TimeUnit unit)
. . . ._ PriorityBlockingQueue<E>
. . . . ._ PriorityBlockingQueue()
. . . . ._ PriorityBlockingQueue(int initialCapacity)
. . . . ._ PriorityBlockingQueue(int initialCapacity, Comparator<? super E> comparator)
. . . ._ BlockinigQueue<E>
. . . . . void put(E element)
. . . . . 添加元素,在必要时阻塞
. . . . . E take()
. . . . . 移除并返回头元素,必要时阻塞
. . . . . boolean offer(E element, long time, TimeUnit unit)
. . . . . 添加给定的元素,如果成功返回true,如果必要时阻塞,直至元素已经被添加或超时
. . . . . E poll(long time, TimeUnit unit)
. . . . . 移除并返回头元素,必要时阻塞,直至元素可用或超时用完,失败时返回null。
. . . . ._ void putFirst(E element)
. . . . ._ void putLast(E element)
. . . . . E takeFirst()
. . . . . 移除并返回头元素,必要时阻塞
. . . . . E takeLast()
. . . . . 移除并返回尾元素,必要时阻塞
. . . . . boolean offerFirst(E element, long time, TimeUnit unit)
. . . . . boolean offerLast(E element, long time, TimeUnit unit)
. . . . . 添加给定的元素,成功时返回true,必要时阻塞直至元素被添加或超时
. . . . . E pollFirst(long time, TimeUnit unit)
. . . . . E pollLast(long time, TimeUnit unit)
. . . . . 移动并返回头元素或尾元素,必要时阻塞,直至元素可用或超时,失败则返回null
. . . ._ TransferQueue<E>
. . . . ._ void transfer(E element)
. . . . . boolean tryTransfer(E element, long time, TimeUnit unit)
. . . . . 传输一个值,或者在给定的时间内传输这个值,这个调用将阻塞,直到另一个线程将元素删除。第二个方法会在调用成功时返回true。
. . 线程安全
. . 的集合
. . . 高效的
. . . 映射/
. . . 集/队列
. . . . ConcurrentHashMap
. . . . ConcurrentSkipListMap
. . . . ConcurrentSkipListSet
. . . . ConcurrentLinkedQueue
. . . ._ 这些集合使用复杂的算法,通过允许并发地访问数据结构的不同部分来使竞争极小化。
. . . ._ 与大多数集合不同,size方法不必在常量时间内操作。确定这样的集合当前的大小通常需要遍历。
. . . ._ 有些应用使用庞大的并发散列映射,这些映射太过庞大,以至于无法用size方能发得到它的大小,因为这个方法只能返回int,java8引入了mappingCount方法,可以把大小作为long返回。
. . . ._ 集合返回弱一致性的迭代器,这意味着迭代器不一定能反映出它们被构造之后的所有的修改,但是它们不会将同一个值返回两次,也不会抛出ConcurrentModificationException异常,然而,集合如果在迭代器构造之后生改变,java.util包中的迭代器会抛出该异常。
. . . ._ 默认情况下,假定可以有多达16个写者线程同时执行,可以有更多的写者线程,但是,如果同一时间多于16个,其他线程将暂时被阻塞,可以指定更大数目的构造器,然而,恐怕没有这个必要。
. . . . 散列映射将相同散列码的所有条目放在同一个桶中,有些应用使用的散列函数不当,以至于所有条目最后都放在很少的桶中,这会严重影响性能。
. . . . String类的散列函数也存在问题,攻击者可能会制造大量有散列值的字符串,让程序速度减慢。java8中,并发散列映射将桶组织为树,而不是列表,键类型实现了Comparable,从而可以保证性能为O(log(n))
. . . ._ api
. . . . ._ ConcurrentLinkedQueue<E>
. . . . . ._ CuncurrentLinkedQueue<E>()
. . . . ._ ConcurrentSkipListSet<E>
. . . . . ._ ConcurrentSkipListSet<E>()
. . . . . ._ ConcurrentSkipListSet<E>(Comparator<? super E> comp)
. . . . ._ ConcurrentHashMap<K,V>
. . . . . ._ ConcurrentHashMap<K,V>()
. . . . . ._ ConcurrentHashMap<K,V>(int initialCapacity)
. . . . . ._ ConcurrentHashMap<K,V>(int initialCapacity, float loadFactor, int concurrencyLevel)
. . . . ._ ConcurrentSkipListMap<K,V>
. . . . . ._ ConcurrentSkipListMap<K,V>()
. . . . . ._ ConcurrentSkipListMap<K,V>(Comparator<? super k> comp)
. . . 映射条目的
. . . 原子更新
. . . . 传统的做法是使用replace操作,它会以原子的方式用一个新值替换原值,前提是之前没有其他线程把原值替换为其他值,必须一直这么做,直到replace成功。
. . . . do
. . . . {
. . . .   oldValue = map.get(word);
. . . .   newValue = oldValue == null ? 1 : oldValue -1;
. . . . } while (!map.replace(word, oldValue, newValue));
. . . . 也可以使用一个ConcurrentHashMap<String, AtomicLong>,或者在java8中使用ConcurrentHashMap<String, LongAdder>,如下:
. . . . map.putIfAbsent(word, new LongAdder());
. . . . map.get(word).increment();
. . . . 或者
. . . . map.putInAbsent(word, new LongAdder()).increment();
. . . . java8提供了更方便的原子更新的方法,调用compute方法时可以提供一个键和一个计算新值的函数
. . . . map.compute(word, (k,v) -> v == null ? 1 : v +1);
. . . . 
. . . . 或者使用computeIfAbsent、computeIfPresent
. . . . map.computeIfAbsent(word, k -> new LongAdder()).increment();
. . . . 
. . . . 可以使用merge
. . . . map.merge(word, 1L, (existingValue,  newValue) -> existingValue + newValue);
. . . . 或者
. . . . map.merge(word, 1L, Long::sum);
. . . . merge方法有一个参数标识键不存在时使用的初始值,否则,就会调用你提供的函数来结合原值与初始值。
. . . . 
. . . . 如果传入compute或merge的函数返回null,将从映射中删除现有的条目。
. . . . 使用compute或merge时,要记住你提供的函数不能做太多工作,这个函数运行时,可能会阻塞对映射的其他更新。
. . . 并发散列映
. . . 射的批操作
. . . ._ java8为并发散列映射提供了批操作,即使有其他线程在处理映射,这些操作也能安全地执行。
. . . ._ 3种不同的操作
. . . . . search搜索为每个键或值提供一个函数,直到函数生成一个非null的结果,然后搜索终止,返回这个函数的结果。
. . . . . U seachKeys(long threshold, BiFunction<? super K, ? extends U> f)
. . . . . U seachValues(long threshold, BiFunction<? super V, ? extends U> f)
. . . . . U seach(long threshold, BiFunction<? super K, ? super V, ? extends U> f)
. . . . . U seachEntries(long threshold, BiFunction<Map.Entry<K,V>, ? extends U> f)
. . . . . 示例:查找第一个出现次数超过1000次以上的单词
. . . . . String result = map.seach(threshold, (k,v) -> v > 1000 ? k : null);
. . . . . reduce规约组合所有的键或值,这里要使用所提供的一个累加函数
. . . . . 示例:用一个累加函数组合其输入
. . . . . Long sum = map.reduceValues(threshold, Long::sum);
. . . . . 示例:也可以提供一个转换器
. . . . . Integer maxLength = map.reduceKeys(threshold, 
. . . . . String::length,   // Transformer
. . . . . Integer::max);   // Accumulator
. . . . . 转换器可以作为一个过滤器,通过返回null排查不想要的输入
. . . . . Long count = map.reduceValues(threshold,
. . . . . v -> v > 1000 ? 1L : null, Long::sum);
. . . . . 如果映射为空,或所有的条目都被过滤掉,reduce返回null, 如果只有一个元素,则不会应用累加器
. . . . . forEach为所有键或值提供一个函数
. . . . . 示例:为各个映射条目提供一个消费者函数
. . . . . map.forEach(threshold, (k,v) -> System.out.println(k + "->" + v));
. . . . . 示例:还可以提供一个转换器函数,该函数需先提供,其结果会传递到消费者
. . . . . map.forEach(threshold, 
. . . . . (k,v) -> k + "->" + v,   // Transformer
. . . . . System.out::println);     // Consumer
. . . . . 示例:转换器可以做为一个过滤器,如果返回null,这个值将会被忽略
. . . . . map.forEach(threshold,
. . . . . (k,v) -> v > 1000  ? k + "->" + v : null,  //Filter and transformer
. . . . . System.out::println);  // The nulls are not passed to the consumer
. . . ._ 每个操作都有4个版本
. . . . ._ operationKeys:处理键
. . . . ._ operationValues:处理值
. . . . ._ operation:处理键和值
. . . . ._ operationEntries:处理Map.Entry对象
. . . . . 对上述操作需要指定一个参数化阈值(parallelism threshold),如果映射包含的元素多于这个阈值,就会并行完成批操作。
. . . . . 如果希望操作在一个线程中执行,可以使用阈值Long.MAX_VALUE
. . . . . 如果希望用尽可能多的线程运行批操作,可以使用阈值1
. . . . . 对于int,long和double输出还有相应的特殊化版本,分别有后缀ToInt,ToLong和ToDouble。需要把输入转换为一个基本类型,并制定一个默认值和一个累加器函数,映射为空时返回默认值
. . . . . long sum = map.reduceValuesToLong(threshold,
. . . . .    Long::longValue, // Transformer to primitive type
. . . . .    0,  // Default value for empty map
. . . . .    Long::sum); // Primitive type accumulator
. . . . . 这些特殊化操作与对象版本操作有所不同,对于对象版本的操作,只需要考虑一个元素,这里不是返回转换器得到的元素,而是将与默认值累加,因此,默认值必须是累加器的零元素。
. . ._ 并发集视图
. . . . 静态newKeySet方法会生成一个Set<K>,这实际上是ConcurrentHashMap<K,Boolean>的一个包装器(所有映射值都是Boolean.TRUE,不过因为只是要把它用作一个集,所以并不关心具体的值)
. . . . Set<String> words = ConcurrentHashMap.<String>newKeySet();
. . . . java8为ConcurrentHashMap增加了第二个KeySet方法,包含一个默认值,可以在为集增加元素时使用
. . . . Set<String> words = map.keySet(1L);
. . . . word.add("java");
. . . . 如果“java”在words中不存在,现在它会有一个默认值1.
. . ._ 写数组拷贝
. . . ._ CopyOnWriteArrayList和CopyOnWriteArraySet是线程安全的集合,其中所有的修改线程对底层数组进行复制。
. . ._ 并行数组算法
. . . . java8中,Arrays类提供了大量的并行化操作,静态Arrays.parallelSort方法可以对一个基本类型值或对象的数组排序。
. . . . String[] words = contents.split("[\\p{L}]+");
. . . . Arrays.parallelSort(words);
. . . . 
. . . . 对对象排序是可以提供一个Comparator
. . . . Arrays.parallelSort(words, Comparator.comparing(String::length));
. . . . 
. . . . 对所有的方法可以提供一个范围的边界
. . . . values.parallelSort(values.length / 2, values.length);
. . . . 
. . . . parallelSetAll方法会用由一个函数计算得到的值填充一个数组,这个函数接收元素索引,然后计算相应位置上的值。
. . . . Arrays.parallenSetAll(values, i -> i % 10);
. . . . 
. . . . 最后还有parallelPrefix方法,它会用对应一个给定结合操作的前缀的累加结果替换各个数组元素,考虑数组[1,2,3,4,...]和x操作
. . . . Arrays.parallelPrefix(values, (x,y)-> x*y);  之后将包含数组
. . . . [1, 1x2, 1x2x3, 1x2x3x4, ...]
. . . 较早的线程
. . . 安全的集合
. . . . ArrayList和HashMap不是线程安全的,而集合库中提供了不同的机制。任何集合类都可以通过同步包装器编程线程安全的。
. . . . List<E> synchArrayList = Collections.synchronizedList(new ArrayList<E>);
. . . . Map<K,V> synchHashMap = Collections.syschronizedMap(new HashMap<K,V>);
. . . . 结果集合的方法使用锁加以保护,提供了线程安全性。
. . . . 如果在另一个线程可能进行修改时要对集合进行迭代,仍然需要使用“客户端”锁定。
. . . . synchronized (synchHashMap)
. . . . {
. . . .   Iterator<K> iter = synchHashMap.keySet().iterator();
. . . .   while(iter.hasNext()) . . .;
. . . . }
. . . . 如果使用forEach循环必须使用同样的代码,因为循环使用了迭代器
. . . ._ 最好使用java.util.concurrent包中定义的集合,不使用同步包装器中的,有一个例外是经常修改的数组列表,在那种情况下,同步的ArrayList可以胜过CopyOnWriteArrayList
. . . ._ api
. . . . ._ Collections
. . . . . . static <E> Collection<E> synchronizedCollection(Collectiion<E> c)
. . . . . . static <E> List synchronizedList(List<E> c)
. . . . . . static <E> Set synchronizedSet(Set<E> c)
. . . . . . static <E> SortedSet synchronizedSortedSet(SortedSet<E> c)
. . . . . . static <K,V> Map<K,V> synchronizedMap(Map<K,V> c)
. . . . . . static <K,V> SortedMap<K,V> synchronizedSortedMap(SorteMap<K,V> c)
. ._ Callable/Future
. . . Runnable封装一个异步运行的任务,没有返回值,Callable与Runnable类似,但是有返回值,
. . . public interface Callable<V>
. . . {
. . .   V call() throws Exception;
. . . }
. . . 
. . . Future保存异步计算的结果
. . . public interface Future<V>
. . . {
. . .   V get() throws . . .;
. . .   V get(long timeout, TimeUnit unit) throws . . .;
. . .   void cancel(boolean mayInterrupt);
. . .   boolean isCancelled();
. . .   boolean isDone();
. . . }
. . . 第一个get调用将阻塞,直到计算完成。
. . . 第二个get设置一个等待超时时间,如果超时将抛出TimeoutException异常
. . . cancel取消该计算
. . . isDone:如果计算仍在进行则返回false, 否则返回true
. . . FutureTask包装器是一个非常便利的机制,可以将Callable转换成Future和Runnable,它同时实现二者的接口
. . . Callable<Integer> myComputation = . . .;
. . . FutureTask<Integer> task = new FutureTask<Integer>(myComputation);
. . . Thread t = new Thread(task);
. . . t.start();
. . . . . .
. . . Integer result = task.get();
. . ._ api
. . . ._ Callable<V>
. . . . ._ V call
. . . ._ Future<V>
. . . . ._ V get()
. . . . ._ V get(long time, TimeUnit unit)
. . . . ._ boolean cancel(boolean mayInterrupt)
. . . . ._ boolean isCancelled()
. . . . ._ boolean isDone()
. . . ._ FutureTask<V>
. . . . ._ FutureTask(Callable<V> task)
. . . . ._ FutureTask(Runnable task, V result)
. ._ 执行器
. . . 执行器类Executor有许多静态工厂方法用来创建线程池
. . . newCachedThreadPool: 必要时创建新线程,空闲线程会被保留60秒
. . . newFixedThreadPool:该池包含固定数量的线程,空闲线程会一直保留
. . . newSingleThreadExecutor:只有一个线程的池,该线程顺序执行每一个提交的任务
. . . newScheduledThreadPool:用于预定义执行而构建的线程池,替代java.util.Timer
. . . newSingleThreadScheduledExecutor:预定执行而构建的单线程池
. . ._ 线程池
. . . . 可以用下列方法之一将一个Runnable对象或Callable对象提交给ExecutorService
. . . . Future<?> submit(Runnable task)
. . . . Future<T> submit(Runnable task, T result)
. . . . Future<T> submit(Callable<T> task)
. . . . 下面总结了使用连接池时应该做的事
. . . . 1.调用Executor类中静态的方法newCachedThreadPool或newFixedThreadPool
. . . . 2.调用submit提交Runnable或Callable对象
. . . . 3.如果想取消一个任务,或如果提交Callable对象,那就要保存好返回的Future对象
. . . . 4.当不再提交任务任务时,调用shutdown
. . . . ExecuteorService pool = Executors.newCachedThreadPool();
. . . . MatchCounter counter = new MatchCounter(new File(directory), keyword, pool);
. . . . Future<Integer> result = pool.submit(counter);
. . . . try 
. . . . {
. . . .   result.get();
. . . . } catch (. . .) 
. . . . {
. . . .   . . .
. . . . }
. . . . pool.shutdown();
. . . . 
. . . . class MatchCounter implements Callable<Integer>
. . . . {
. . . .   public Integer call()
. . . .   {
. . . .    . . .
. . . .   }
. . . . }
. . . ._ api
. . . . ._ Executors
. . . . . ._ ExecuteorService newCachedThreadPool()
. . . . . ._ ExecutorService newFixedThreadPool(int threads)
. . . . . ._ ExecutorService newSingleThreadExecutor()
. . . . ._ ExecutorService
. . . . . . Future<?> submit(Runnable task)
. . . . . . Future<T> submit(Runnable task, T result)
. . . . . . Future<T> submit(Callable<T> task)
. . . . ._ ThreadPoolExecutor
. . . . . ._ int getLargestPollSize()
. . ._ 预定执行
. . . ._ SchedulerdExecutorService接口具有为预定执行或重复执行任务而设计的方法
. . . ._ api
. . . . ._ Executors
. . . . . ._ ScheduledExecutorService newScheduledThreadPool(int threads)
. . . . . ._ SchduledExecutorService newSingleThreadScheduledExecutor()
. . . . ._ ScheduledExecutorSercvice
. . . . . ._ ScheduledFuture<V> schedule(Callable<V> task, long time, TimeUnit unit)
. . . . . ._ ScheduledFuture<?> schedule(Runnable task, long time, TimeUnit unit)
. . . . . ._ ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit)
. . . . . ._ ScheduledFuture<?> scheduledWithFixedDelay(Runnable task, long initialDelay, long delay, TimeUnit unit)
. . ._ 控制任务组
. . . . 使用执行器有更实际意义的原因,控制一组相关任务
. . . . shutdownNow方法取消所有任务
. . . . invokeAny方法提交所有对象到一个Callable对象的集合中,并返回某个已经完成了的任务结果
. . . . invokeAll方法提交所有对象到一个Callable对象的集合中,并返回一个Future对象的列表
. . . ._ api
. . . . ._ ExecutorService
. . . . . . T invokeAny(Collection<Callable<T>> tasks)
. . . . . . T invokeAny(Collection<Callable<T>> tasks, long timeout, Timeout unit)
. . . . . . List<Future<T>> invokeAll(Collection<Callable<T>> tasks)
. . . . . . List<Future<T>> invokeAll(Collectiion<Callable<T>> tasks, long timeout, Timeout unit)
. . . . ._ ExecutorCompletionService<V>
. . . . . ._ ExecutorCompletionService(Executor e)
. . . . . ._ Future<V> submit(Callable<V> task)
. . . . . ._ Future<V> submit(Runnable task, V result)
. . . . . ._ Future<V> take()
. . . . . ._ Future<V> poll()
. . . . . ._ Future<V> poll(long time, Timeout unit)
. . ._ Fork-join
. . . ._ java7引入了fork-join框架,专门支持多线程情况下,将一个处理任务很自然地分解为子任务。
. . . ._ 需要供一个RecursiveTask<T>的类(如果计算会生成一个类型为T的结果)或者提供一个扩展RecursiveAction的类(如果不生成任何结果),再覆盖compute方法来生成调用子任务,然后合并其结果。
. . . . class Counter extends RecursiveTask<Integer>
. . . . {
. . . .   . . .
. . . .   protected Integer compute()
. . . .   {
. . . .     if (to - from < THRESHOLD)
. . . .     {
. . . .        solve problem directly
. . . .     }
. . . .     else
. . . .     {
. . . .        int mid = (from + to) /2;
. . . .        Counter first = new Counter(values, from, mid, filter);
. . . .        Counter second = new Counter(values, mid, to, filter);
. . . .        invokeAll(first, second);
. . . .        return first.join() + second.join();
. . . .     }
. . . .   }
. . . . }
. . . . involeAll方法接收到很多任务并阻塞,指导所有的任务已经完成,join方法将生成结果。
. . . ._ 在后台,fork-join框架使用了一种有效的智能方法来平衡可用线程的工作负载,这种方法称为工作密取(work stealing),每个工作线程都有一个双端队列来完成任务,一个工作线程将子任务压入双端队列的队头,(只有一个线程可以访问队头,所以不用加锁)一个工作线程空闲时,它会从另一个双端队列的队尾密取任务。
. . . . public class ForkJionTest
. . . . {
. . . .   public static void main(String[] args)
. . . .   {
. . . .     final int SIZE = 10000000;
. . . . 	double[] numbers = new double[SIZE];
. . . . 	for (int i = 0; i < SIZE; i++) numbers[i] = Math.random();
. . . . 	Counter counter = new Counter(numbers, 0, numbers.length, x->x > 0.5);
. . . . 	ForkJionPool pool = new ForkJoinPool();
. . . . 	pool.invoke(counter);
. . . . 	System.out.println(counter.join());
. . . .   }
. . . .   
. . . .   class Counter extends RecursiveTask<Integer>
. . . .   {
. . . . 	public Counter(double[] values, int from, int to, DoublePredicate filter)
. . . . 	{
. . . . 	  this.values = values;
. . . . 	  this.from = from;
. . . . 	  this.to = to;
. . . . 	  this.filter = filter;
. . . . 	}
. . . . 	
. . . . 	pritected Integer compute()
. . . . 	{
. . . . 	  . . .
. . . . 	}
. . . .   }
. . . . }
. . ._ 可完成Future
. . . ._ 处理非阻塞调用的传统方法是使用事件处理器,java8的CompletableFuture提供了一种候选方案,与事件处理器不同,可完成future可以组合。
. . . . web页面可用时返回该页面的文本:
. . . . public void CompeltableFuture<String> readPage(URL url)
. . . . 生成一个html页面中的URL列表:
. . . . public static List<URL> getLinks(String page)
. . . . CompletableFuture<String> contents = readPage(url);
. . . . CompletableFuture<List<URL>> links = contents.thenApply(Parser::getLinks)
. . . . thenApply方法不会阻塞,它会返回另一个future,第一个future完成时,其结果会提供给getLInks方法,这个方法的返回值就是最终的结果。
. . . ._ 利用可完成future,可以指定你希望做什么,或希望以什么顺序执行这些工作。
. . . . 处理单个future的方法
. . . . 每个方法都有两个Async
. . . . 的形式
. . . . ._ thenApply
. . . . . ._ T->U
. . . . . . ._ 对结果应用一个函数
. . . . ._ thenCompose
. . . . . ._ T->CompletableFuture<U>
. . . . . . ._ 对结果调用函数并执行返回的future
. . . . ._ handle
. . . . . ._ (T,Throwable)->U
. . . . . . ._ 处理结果或错误
. . . . ._ thenAccept
. . . . . ._ T-void
. . . . . . ._ 类似于thenApply,不过结果为void
. . . . ._ whenComplete
. . . . . ._ (T,Throwable)->U
. . . . . . ._ 类似于handle,不过结果为void
. . . . ._ thenRun
. . . . . ._ Runnable
. . . . . . ._ 执行Runnable,结果为void
. . . ._ 组合多个future的方法
. . . . ._ thenCombine
. . . . . ._ 执行两个动作,并用给定函数组合结果
. . . . ._ thenAceeptBoth
. . . . . ._ 类似thenCombine,结果为void
. . . . ._ runAfterBoth
. . . . . ._ 两个都完成后执行runnable
. . . . ._ applyToEither
. . . . . ._ 得到其中一个结果时,传入给定的函数
. . . . ._ accepyEither
. . . . . ._ 与applyToEither类似,结果为void
. . . . ._ runAfterEither
. . . . . ._ 其中一个完成后执行runnable
. . . . ._ static allOf
. . . . . ._ 所有给定的future都完成后完成,结果为void
. . . . ._ static anyOf
. . . . . ._ 任意给定的future完成则完成,结果为void
. . . . ._ 前3个方法并行运行一个CompletableFuture<T>和一个CompletableFuture<U>动作,并组合结果
. . . . ._ 接下来3个方法并行运行两个CompletableFuture<T>动作,一旦其中一个动作完成,就传递它的结果,并忽略另一个结果。
. . . . ._ 最后静态的allOf和anyOf方法取一组可完成future,并生成一个CompletableFuture<Void>,它会在所有这些future都完成时或者其中任意一个future完成时结束
. ._ 同步器
. . ._ 介绍
. . . ._ CyclicBarrirer:运行线程集等待直至其中预定数目的线程到达一个公共障珊,然后可以选择执行一个处理障珊的动作
. . . . ._ 当大量线程需要在它们的结果可用之前完成时
. . . ._ Parser:类似于循环障珊,不过有一个可变的计数
. . . . ._ java7中引入
. . . ._ CountDownLatch:允许线程集等待直到计数器减为0
. . . . ._ 当一个或多个线程需要等待直到指定数目的事件发生
. . . ._ Exchanger:允许两个线程在要交换的对象准备好时交换对象
. . . . ._ 当两个线程工作在同一数据结构的两个实例上的时候,一个向实例添加数据,而另一个从实例清除数据
. . . ._ Semaphore:允许线程集等到直到允许继续运行为止
. . . . ._ 限制访问资源的线程总数,如果许可数时1,常常阻塞线程直到另一线程给出许可为止
. . . ._ SynchronousQueue:允许一个线程把对象交给另一个线程
. . . . ._ 在没有显示同步的情况下,当两个线程准备好将一个对象从一个线程传递到另一个时
. . ._ 信号量
. . . ._ 一个信号量管理许多许可证,为了通过信号量,线程调用acquire请求许可。其实没有实际的许可对象,信号量仅维护一个计数,许可的数目是固定的,其他线程可调用release释放许可
. . ._ 倒计时门栓
. . . ._ 一个倒计时门栓(CountDownLatch)让一个线程集等待直到计数变为0,倒计时门栓是一次性的,一旦计数器变为0,就不能再重用了
. . ._ 障珊
. . . ._ CyclicBarrier类实现了一个集结点,称为障珊,例如大量线程运行一个计算的不同部分的情景,当有部分准备好时需要把结果组合在一起,一旦所有线程都到达障珊,障珊就取消,线程就可以继续运行。
. . . . CyclicBarrier barirer = new CyclicBarrier();
. . . . public run()
. . . . {
. . . .   doWork();
. . . .   barrier.await();
. . . .   . . .
. . . . }
. . . ._ 如果任意一个在障珊上等待的线程离开了障珊,障珊就被破坏了,这种情况下,所有其他线程的await方法将抛出BrokenBarrierException异常
. . . . 可以提供一个可选的障珊动作,当所有线程到达障珊的时候就会执行这一动作
. . . . Runnable barrierAction = ...;
. . . . CyclicBarrier barriver = new CyclicBarrier(nthreads, barrierAction);
. . . ._ 障珊被称为循环的,因为可以在所有等待线程被释放后重复使用,而CountDownLatch只能被使用一次
. . ._ 交换器
. . . ._ 当两个线程在同一个数据缓冲区的两个实例上工作的时候,就可以使用交换器,典型的情况是,一个线程向缓冲区填入数据,另一个线程消耗这些数据,当它们都完成以后,相互交换缓冲区
. . ._ 同步队列
. . . ._ 同步队列是一种生产者和消费者配对的机制,当一个线程调用SynchronousQueue的put方法时,它会阻塞直到另一个线程调用take方法为止,反之亦然。与Exchanger不同,数据仅沿着一个方向移动,即从生产者到消费者。
. . . ._ 即使SynchronousQueue类实现了BlockingQueue接口,它依然不是一个队列,它没有包含任何元素,它的size方法总是返回0

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值