02-Collection
Collection => 不支持普通for循环(无index)
- List => 有序,不唯一。拓展的API都和index有关
Vector
(线程安全)效率低,淘汰- 底层为数组,扩容策略2倍
ArrayList
(线程不安全):源码类似StringBuilder- JDK7底层为数组(饿汉式),构造器数组长度初始化10,扩容策略1.5倍
- JDK8底层为数组(懒汉式),构造器数组为{},
add()
数组长度为10,扩容策略1.5倍
LinkedList
- JDK8底层双向链表
- Set => 无序,唯一。无index
HashSet
:哈希表LinkedHashSet
:哈希表 + 链表- 有序(输入顺序)
TreeSet
- 有序(自定义顺序)。二叉树。类必须实现Comparator
1. Collection
1. API
/*
* Collection_API
*
* 1. 增加:add(E e), addAll(Collection<? extends E> c)
* 2. 删除:clear(), remove(Object o)
* 3. 修改:
* 4. 查看:iterator(), size()
* 5. 判断:contains(Object o), equals(Object o), isEmpty()
*/
@Test
public void T1_API() {
Collection<Object> col = new ArrayList<>();
// 集合特点:只能存放引用数据类型,不能存基本类型
// 基本数据类型对应包装类。int => Integer
col.add(18);
col.add(12);
col.add(11);
col.add(17);
// 默认.toString()
System.out.println("col = " + col);
List<Object> list = Arrays.asList(11, 15, 3, 7, 1);
col.addAll(list); // 将另一个集合添加入col中
System.out.println("col = " + col);
boolean isRemove = col.remove(15);
System.out.println("删除15 = " + col);
Collection<Object> col2 = new ArrayList<>();
col2.add(18);
col2.add(12);
col2.add(11);
col2.add(17);
Collection<Object> col3 = new ArrayList<>();
col3.add(18);
col3.add(12);
col3.add(11);
col3.add(17);
System.out.println("equals: " + col2.equals(col3));
System.out.println("==: " + (col2 == col3)); // false,地址一定不相等
System.out.println("contains: " + col3.contains(117));
col.clear(); // 清空集合
System.out.println("col.size() = " + col.size());
System.out.println("col.isEmpty() = " + col.isEmpty());
}
2. 遍历
/**
* 1. 普通fori循环。无index无法进行
* 2. 增强for循环
* 3. iterator()
*/
@Test
public void T2_iterator() {
Collection<Object> col = Arrays.asList(18, 12, 11, 17, "abc", 9.8);
// 方式1:普通for循环。无index无法进行
for (int i = 0; i < col.size(); i++) {
// col.
}
// 方式2:增强for循环
for (Object o : col) {
System.out.println(o);
}
System.out.println("------------------------");
// 方式3:iterator()
Iterator<Object> it = col.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
2. List
- 相较
Collection
接口,增加有关index抽象方法
1. API
/*
* List
*
* 1. 增加:add(int index, E element)
* 2. 删除:remove(int index), remove(Object o)
* 3. 修改:set(int index, E element)
* 4. 查看:get(int index)
* 5. fori
*/
@Test
public void T1_API() {
List<Object> list = new ArrayList<>();
list.add(13);
list.add(17);
list.add(6);
list.add(-1);
list.add(2);
list.add("abc");
System.out.println(list);
// 1. add(int index, E element);
list.add(3, 66);
System.out.println("add() = " + list);
// 2. set(int index, E element);
list.set(3, 77);
System.out.println("set() = " + list);
// 3.1. remove(int index);
list.remove(2);
System.out.println("remove() = " + list);
// 3.2. remove(Object o);
list.remove("abc");
System.out.println(list);
// 4. get(int index);
Object o = list.get(0);
System.out.println("get(0) = " + o);
System.out.println("==============================");
// 5.1. 普通for循环
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println("==============================");
// 5.2. 增强for循环(底层为iterator)
for (Object obj : list) {
System.out.println(obj);
}
System.out.println("==============================");
// 5.3. 迭代器
Iterator<Object> it = list.iterator();
while (it.hasNext()) {
int next = (int) it.next();
if (next == 17) {
it.remove();
} else {
System.out.println(next);
}
}
System.out.println(list);
}
3. ArrayList
- 默认数组长度:10
Object[]
扩容策略1.5倍- 懒汉式。
add()
时,底层数组长度变为10
/**
* 1. 默认数组长度:10
* 2. Object[]扩容策略1.5倍
* 3. 懒汉式。`add()`时,底层数组长度变为10
*/
@Test
public void T2_ArrayList_SC() {
// 底层数组为{},length为0
ArrayList<Object> noArgs = new ArrayList<>();
// add(),Object[].length = 10
noArgs.add("ooxx");
// Object[].length = 3
ArrayList<Object> args = new ArrayList<>(3);
}
1. SC
// 集合创始人承认这个失误,但在后续的版本中没有删除,觉得没必要
// class AbstractList<E> extends AbstractCollection<E> implements List<E>
class _ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
// 1. 底层数组
transient Object[] elementData;
// list长度
private int size;
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 2. 默认数组长度
private static final int DEFAULT_CAPACITY = 10;
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 无参构造
*/
public _ArrayList() {
super();
this.elementData = EMPTY_ELEMENTDATA;
}
/**
* 有参构造。指定数组长度
*/
public _ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
}
}
public boolean add(E e) {
// 3.1. 确认容量
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
// 3.2. 计算最小容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
// 第一次add(),Object[]默认长度10
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // {}
return Math.max(DEFAULT_CAPACITY, minCapacity); // 10
}
return minCapacity;
}
// 3.3. 判断是否扩容
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 最小容量 > Object[]容量
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
// 3.4. 扩容。1.5倍容量
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
// Object[]扩容1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 扩容容量 < 最小容量,取最小长度
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// old[] => new[]
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0)
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
@Override
public E get(int index) {
// rangeCheck(index);
return elementData(index);
}
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
@Override
public int size() {
return size;
}
}
4. Vector
- 默认底层数组长度:10(饿汉式)
Object[]
扩容策略2倍- 所有方法被
synchronized
修饰
/**
* 1. 默认底层数组长度:10(饿汉式)
* 2. Object[]扩容策略2倍
* 3. 所有方法被`synchronized`修饰
*/
@Test
public void T3_Vector_SC() {
// Object[].length = 10
Vector<String> noArgs = new Vector<>();
noArgs.add("ooxx");
// Object[].length = 3
Vector<String> args = new Vector<>(3);
}
1. SC
class _Vector<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
// 1. 底层数组
protected Object[] elementData;
// 容器长度
protected int elementCount;
protected int capacityIncrement;
// 2. 默认数组长度10(饿汉式)
public _Vector() {
this(10);
}
public _Vector(int initialCapacity) {
this(initialCapacity, 0);
}
public _Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
// 饿汉式init
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
// ** synchronized **
public synchronized boolean add(E e) {
modCount++;
// 3. 确认容量
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
// 3.1. 判断是否扩容
private void ensureCapacityHelper(int minCapacity) {
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
// 3.2. 扩容。2倍容量
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
// Object[]扩容2倍
int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// old[] => new[]
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0)
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
@Override
public E get(int index) {
return null;
}
@Override
public int size() {
return 0;
}
}
5. Stack
- Stack和Vector都被淘汰
class Stack<E> extends Vector<E>
- 后进先出(LIFO,last in first out)
/**
* 1. Stack和Vector都被淘汰
* 2. `class Stack<E> extends Vector<E>`
* 3. 后进先出(LIFO,last in first out)
*/
@Test
public void T4_Stack() {
Stack<String> s = new Stack<>();
// 返回boolean
s.add("A");
s.add("B");
s.add("C");
s.add("D");
System.out.println("s = " + s);
System.out.println("s.empty() = " + s.empty());
System.out.println("查看栈顶元素,s.peek() = " + s.peek());
System.out.println("弹出栈顶元素,s.pop() = " + s.pop());
// add()功能一样,返回<E>
s.push("D");
System.out.println("s = " + s);
}
1. 应用
- 内存分析:形参,局部变量放入栈中(堆:利用完全二叉树结构来维护一组数据)
- 网络浏览器“后退”按钮
- 文本编辑器撤销功能(ctrl + z:撤销)
6. LinkedList
- ArrayList
- 物理结构:紧密结构 => 数组
- 逻辑结构:线性表
- LinkedList
- 物理结构:跳转结构 => 双向链表
- 逻辑结构:线性表
1. API
List.add(e), Deque.offer(e)
区别void, boolean
Deque.poll(), Deque.remove()
区别null, NoSuchElementException
public class T3_LinkedList {
/*
* 1. 增加
* addFirst(E e), addLast(E e)
* offer(E e), offerFirst(E e), offerLast(E e)
* 2. 删除
* poll(), pollFirst(), pollLast() => JDK1.6后方法,提高健壮性
* removeFirst(), removeLast()
* 3. 修改
* 4. 查看
* element()
* getFirst(), getLast()
* indexOf(Object o), lastIndexOf(Object o)
* peek(), peekFirst(), peekLast()
* 5. 判断
*/
@Test
public void API() {
LinkedList<String> list = new LinkedList<>();
// 1.1. add() => void
list.add("11");
list.addFirst("22");
list.addLast("33");
System.out.println(list);
// 1.2. offer() => boolean
boolean offer = list.offer("44");
boolean offerFirst = list.offerFirst("55");
boolean offerLast = list.offerLast("66");
// 可以添加重复数据
System.out.println(list);
// 2.1. poll() => null
System.out.println("list.poll() = " + list.poll());
System.out.println("list.pollFirst() = " + list.pollFirst());
System.out.println("list.pollLast() = " + list.pollLast());
System.out.println(list);
// 2.2. remove() => NoSuchElementException
System.out.println("list.removeFirst() = " + list.removeFirst());
System.out.println("list.removeLast() = " + list.removeLast());
System.out.println(list);
// 2.3. 清空
list.clear();
System.out.println(list);
list.add("iterator");
// 4.1. 普通for
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
// 4.2. 增强for
for (String s : list) {
System.out.println(s);
}
// 4.3. 迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
@Test
public void SC() {
// 无界,无参构造
LinkedList<Integer> ints = new LinkedList<>();
ints.add(1);
}
}
2. SC
- JDK1.7、JDK1.8的LinkedList源码一致
- 无界,只能无参构造
- Node内部类,
item, next, prev
get()
二分index遍历
class _LinkedList<E> {
// 1. Node内部类
private static class Node<E> {
E item; // 当前元素
Node<E> next; // 下一个元素
Node<E> prev; // 上一个元素
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
transient Node<E> first; // 首节点
transient Node<E> last; // 尾节点
transient int size = 0; // 容器长度
public _LinkedList() {
}
// 2.1. 添加操作
public boolean add(E e) {
linkLast(e);
return true;
}
// 2.2. 添加算法
void linkLast(E e) {
final Node<E> l = last;
// 维护了prev
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
// 第一个节点
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
}
// 3. 容器长度
public int size() {
return size;
}
// 4.1. 索引获取元素
public E get(int index) {
// checkElementIndex(index); 健壮性考虑
return node(index).item;
}
// 4.2. 索引遍历算法
Node<E> node(int index) {
// index在链表前半段,从前往后找
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
}
// index在链表后半段,从后往前找
else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
}
7. Set
public class T4_Set {
@Data
@ToString
@AllArgsConstructor
static class Student implements Comparable<Student> {
Integer age;
String name;
@Override
public int compareTo(Student o) {
return this.getAge() - o.getAge();
}
}
}
/**
* 1. API和Collection一致
* 2. 没有index相关的方法
* 3. 无普通for循环
*/
@Test
public void API() {
Set<Integer> hsi = new HashSet<>();
System.out.println("hsi.add(19) = " + hsi.add(19));
hsi.add(5);
hsi.add(20);
System.out.println("hsi.add(19) = " + hsi.add(19));
hsi.add(41);
hsi.add(0);
// 唯一、无序
System.out.println("hsi.size() = " + hsi.size());
System.out.println(hsi);
System.out.println("-----------------------------------------");
Set<Student> hs = new HashSet<>();
hs.add(new Student(1, "a"));
hs.add(new Student(19, "b"));
hs.add(new Student(20, "d"));
hs.add(new Student(18, "c"));
System.out.println("hs.add(new Student(19, w)) = " + hs.add(new Student(19, "w"))); // true 进行覆盖
hs.add(new Student(10, "t"));
System.out.println("hs.size() = " + hs.size());
// Student(id=19, name=lili)出现了2次
System.out.println(hs);
}
1. HashSet
- 特点
- 基本类型(唯一、无序)
- 自定义引用类型(唯一、无序),需要重写
hashCode(), equals()
- 底层原理 => HashMap的key,永远无法进行覆盖
- 哈希表 = 数组 + 链表
hashCode()
+ 算法 => 数组位置equals()
=> 链表位置- map_value都一样,
PRESENT
1. SC
class _HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable {
private transient HashMap<E, Object> map;
private static final Object PRESENT = new Object();
// 1. 底层HashMap
public _HashSet() {
map = new HashMap<>();
}
// 2. map_value都一样,PRESENT
public boolean add(E e) {
return map.put(e, PRESENT) == null;
}
@Override
public Iterator<E> iterator() {
return null;
}
@Override
public int size() {
return 0;
}
}
2. LinkedHashSet
- 唯一、有序(输入顺序)
- 底层 LinkedHashMap
LinkedHashMap.Entry
继承自HashMap.Node
,额外增加了before, after
。元素之间维护一条双向链表
/**
* 1. 唯一、有序(输入顺序)
* 2. 底层LinkedHashMap
* 3. `LinkedHashMap.Entry`继承自`HashMap.Node`,额外增加了`before(), after()`。元素之间维护一条双向链表
*/
@Test
public void LinkedHashSet() {
LinkedHashSet<String> lhs = new LinkedHashSet<>();
lhs.add("hello");
lhs.add("apple");
lhs.add("banana");
lhs.add("html");
lhs.add("apple");
lhs.add("css");
// 1. 少一个 2. 输入顺序
System.out.println("lhs.size() = " + lhs.size());
System.out.println(lhs);
}
1. SC
public class LinkedHashSet<E> extends HashSet<E> implements Set<E>, Cloneable, Serializable {
public LinkedHashSet() {
super(16, .75f, true);
}
}
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable {
private transient HashMap<E,Object> map;
private static final Object PRESENT = new Object();
public HashSet() {
map = new HashMap<>();
}
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
}
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> {
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
}
3. TreeSet
- 唯一, 有序(升序遍历)
- 底层TreeMap的key(二叉树,中序遍历),永远无法覆盖
- 比较需要Comparator
/**
* 1. 唯一, 有序(升序遍历)
* 2. 底层TreeMap(二叉树,中序遍历)
* 3. 比较需要Comparator
*/
@Test
public void TreeSet() {
TreeSet<Integer> ts_int = new TreeSet<>();
ts_int.add(12);
ts_int.add(3);
ts_int.add(7);
ts_int.add(9);
ts_int.add(3);
ts_int.add(16);
// 1. 少一个 2. 升序
System.out.println("ts_int.size() = " + ts_int.size());
System.out.println(ts_int);
System.out.println("-----------------------------------------");
TreeSet<String> ts_str = new TreeSet<>();
ts_str.add("e");
ts_str.add("b");
ts_str.add("a");
ts_str.add("d");
ts_str.add("c");
ts_str.add("d");
// 1. 少一个 2. 字母顺序
System.out.println("ts_str.size() = " + ts_str.size());
System.out.println(ts_str);
System.out.println("-----------------------------------------");
// 内部比较器
TreeSet<Student> ts_stu = new TreeSet<>();
ts_stu.add(new Student(10, "e"));
ts_stu.add(new Student(8, "b"));
ts_stu.add(new Student(4, "a"));
ts_stu.add(new Student(9, "e"));
System.out.println("ts_stu.add(new Student(8, f)) = " + ts_stu.add(new Student(8, "f"))); // false 加不进去
ts_stu.add(new Student(1, "d"));
System.out.println("ts_stu.size() = " + ts_stu.size());
System.out.println(ts_stu);
System.out.println("-----------------------------------------");
// 外部比较器
Comparator<Student> com_stu = Comparator.comparingInt(Student::getAge).reversed();
TreeSet<Student> ts_outer = new TreeSet<>(com_stu);
ts_outer.add(new Student(10, "e"));
ts_outer.add(new Student(8, "b"));
ts_outer.add(new Student(4, "a"));
ts_outer.add(new Student(9, "e"));
System.out.println("ts_outer.add(new Student(8, f)) = " + ts_outer.add(new Student(8, "f")));
ts_outer.add(new Student(1, "d"));
System.out.println("ts_outer.size() = " + ts_outer.size());
System.out.println(ts_outer);
}
1. SC
class _TreeSet<E>
// extends AbstractSet<E> implements NavigableSet<E>, Cloneable, Serializable
{
// TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>
private transient NavigableMap<E, Object> m;
private static final Object PRESENT = new Object();
// 1. 底层TreeMap
public _TreeSet() {
this(new TreeMap<E, Object>());
}
_TreeSet(NavigableMap<E, Object> m) {
this.m = m;
}
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
// 2. map_value都一样,PRESENT
public boolean add(E e) {
return m.put(e, PRESENT) == null;
}
}
8. Collections
1. API
/**
* Collections构造器私有化,方法都static
*/
public class T5_Collections {
/**
* 1. addAll():添加
* 2. sort():排序 => 升序
* 3. binarySearch():二分查询 => 集合有序
* 4. copy():替换方法
* 5. fill():填充
*/
@Test
public void API() {
ArrayList<String> list = new ArrayList<>();
list.add("aa");
list.add("cc");
list.add("bb");
// 1. addAll():添加
Collections.addAll(list, "dd", "ee", "ff");
System.out.println("addAll() = " + list);
// 2. sort():排序 => 升序
Collections.sort(list);
System.out.println("sort() = " + list);
// 3. binarySearch():二分查询 => 集合有序
System.out.println("binarySearch() = " + Collections.binarySearch(list, "cc"));
// 4. copy():替换方法
ArrayList<String> list2 = new ArrayList<>();
Collections.addAll(list2, "xx", "yy");
Collections.copy(list, list2); // 将list2元素覆盖到list
System.out.println("list2_copy() = " + list2);
System.out.println("list_copy() = " + list);
// 5. fill():填充
Collections.fill(list2, "zzz");
System.out.println("fill() = " + list2);
}
}
addAll() = [aa, cc, bb, dd, ee, ff]
sort() = [aa, bb, cc, dd, ee, ff]
binarySearch() = 2
list2_copy() = [xx, yy]
list_copy() = [xx, yy, cc, dd, ee, ff]
fill() = [zzz, zzz]
2. sync
List<String> list;
// ArrayList、HashMap,线程不安全
@Test
public void thread_unsafe() {
list = new ArrayList<>();
ooxx();
}
// to线程安全
@Test
public void toSync_SC() {
list = Collections.synchronizedList(new ArrayList<>());
ooxx();
}
private void ooxx() {
ExecutorService es = Executors.newFixedThreadPool(100);
for (int i = 0; i < 10_000; i++) {
es.execute(() -> list.add("aaa"));
}
es.shutdown();
// 监控
while (true) {
if (es.isTerminated()) {
System.out.println("list.size() = " + list.size());
break;
}
}
}
class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable
public class Collections {
// 1. async() => sync() 泛型方法
public static <T> List<T> synchronizedList(List<T> list) {
return (list instanceof RandomAccess ?
// 2.1.
new SynchronizedRandomAccessList<>(list) :
new SynchronizedList<>(list));
}
// 2.2.
static class SynchronizedRandomAccessList<E> extends SynchronizedList<E> implements RandomAccess {
// 3.1.
SynchronizedRandomAccessList(List<E> list) {
super(list);
}
}
// 3.2.
static class SynchronizedList<E> extends SynchronizedCollection<E> implements List<E> {
final List<E> list;
SynchronizedList(List<E> list) {
// 4.1.
super(list);
this.list = list;
}
}
static class SynchronizedCollection<E> implements Collection<E>, Serializable {
final Collection<E> c; // Backing Collection
final Object mutex; // Object on which to synchronize
// 4.2.
SynchronizedCollection(Collection<E> c) {
this.c = c;
mutex = this;
}
// 5. **加锁**
public boolean add(E e) {
synchronized (mutex) {
return c.add(e);
}
}
// ...
}
}