|
20 | 20 | import java.lang.ref.SoftReference; |
21 | 21 | import java.lang.ref.WeakReference; |
22 | 22 | import java.lang.reflect.Array; |
| 23 | +import java.util.AbstractCollection; |
23 | 24 | import java.util.AbstractMap; |
24 | 25 | import java.util.AbstractSet; |
| 26 | +import java.util.Collection; |
25 | 27 | import java.util.Collections; |
26 | 28 | import java.util.EnumSet; |
27 | 29 | import java.util.HashSet; |
28 | 30 | import java.util.Iterator; |
29 | 31 | import java.util.Map; |
30 | 32 | import java.util.NoSuchElementException; |
31 | 33 | import java.util.Set; |
| 34 | +import java.util.Spliterator; |
| 35 | +import java.util.Spliterators; |
32 | 36 | import java.util.concurrent.ConcurrentHashMap; |
33 | 37 | import java.util.concurrent.ConcurrentMap; |
34 | 38 | import java.util.concurrent.atomic.AtomicInteger; |
@@ -101,7 +105,17 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen |
101 | 105 | /** |
102 | 106 | * Late binding entry set. |
103 | 107 | */ |
104 | | - private volatile @Nullable Set<Map.Entry<K, V>> entrySet; |
| 108 | + private @Nullable Set<Map.Entry<K, V>> entrySet; |
| 109 | + |
| 110 | + /** |
| 111 | + * Late binding key set. |
| 112 | + */ |
| 113 | + private @Nullable Set<K> keySet; |
| 114 | + |
| 115 | + /** |
| 116 | + * Late binding values collection. |
| 117 | + */ |
| 118 | + private @Nullable Collection<V> values; |
105 | 119 |
|
106 | 120 |
|
107 | 121 | /** |
@@ -512,6 +526,26 @@ public Set<Map.Entry<K, V>> entrySet() { |
512 | 526 | return entrySet; |
513 | 527 | } |
514 | 528 |
|
| 529 | + @Override |
| 530 | + public Set<K> keySet() { |
| 531 | + Set<K> keySet = this.keySet; |
| 532 | + if (keySet == null) { |
| 533 | + keySet = new KeySet(); |
| 534 | + this.keySet = keySet; |
| 535 | + } |
| 536 | + return keySet; |
| 537 | + } |
| 538 | + |
| 539 | + @Override |
| 540 | + public Collection<V> values() { |
| 541 | + Collection<V> values = this.values; |
| 542 | + if (values == null) { |
| 543 | + values = new Values(); |
| 544 | + this.values = values; |
| 545 | + } |
| 546 | + return values; |
| 547 | + } |
| 548 | + |
515 | 549 | private <T> @Nullable T doTask(@Nullable Object key, Task<T> task) { |
516 | 550 | int hash = getHash(key); |
517 | 551 | return getSegmentForHash(hash).doTask(hash, key, task); |
@@ -940,7 +974,7 @@ private interface Entries<V> { |
940 | 974 | /** |
941 | 975 | * Internal entry-set implementation. |
942 | 976 | */ |
943 | | - private class EntrySet extends AbstractSet<Map.Entry<K, V>> { |
| 977 | + private final class EntrySet extends AbstractSet<Map.Entry<K, V>> { |
944 | 978 |
|
945 | 979 | @Override |
946 | 980 | public Iterator<Map.Entry<K, V>> iterator() { |
@@ -976,13 +1010,133 @@ public int size() { |
976 | 1010 | public void clear() { |
977 | 1011 | ConcurrentReferenceHashMap.this.clear(); |
978 | 1012 | } |
| 1013 | + |
| 1014 | + @Override |
| 1015 | + public Spliterator<Map.Entry<K, V>> spliterator() { |
| 1016 | + return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.CONCURRENT); |
| 1017 | + } |
| 1018 | + } |
| 1019 | + |
| 1020 | + /** |
| 1021 | + * Internal key-set implementation. |
| 1022 | + */ |
| 1023 | + private final class KeySet extends AbstractSet<K> { |
| 1024 | + @Override |
| 1025 | + public Iterator<K> iterator() { |
| 1026 | + return new KeyIterator(); |
| 1027 | + } |
| 1028 | + |
| 1029 | + @Override |
| 1030 | + public int size() { |
| 1031 | + return ConcurrentReferenceHashMap.this.size(); |
| 1032 | + } |
| 1033 | + |
| 1034 | + @Override |
| 1035 | + public boolean isEmpty() { |
| 1036 | + return ConcurrentReferenceHashMap.this.isEmpty(); |
| 1037 | + } |
| 1038 | + |
| 1039 | + @Override |
| 1040 | + public void clear() { |
| 1041 | + ConcurrentReferenceHashMap.this.clear(); |
| 1042 | + } |
| 1043 | + |
| 1044 | + @Override |
| 1045 | + public boolean contains(Object k) { |
| 1046 | + return ConcurrentReferenceHashMap.this.containsKey(k); |
| 1047 | + } |
| 1048 | + |
| 1049 | + @Override |
| 1050 | + public Spliterator<K> spliterator() { |
| 1051 | + return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.CONCURRENT); |
| 1052 | + } |
| 1053 | + } |
| 1054 | + |
| 1055 | + /** |
| 1056 | + * Internal key iterator implementation. |
| 1057 | + */ |
| 1058 | + private final class KeyIterator implements Iterator<K> { |
| 1059 | + |
| 1060 | + private final Iterator<Map.Entry<K, V>> iterator = entrySet().iterator(); |
| 1061 | + |
| 1062 | + @Override |
| 1063 | + public boolean hasNext() { |
| 1064 | + return this.iterator.hasNext(); |
| 1065 | + } |
| 1066 | + |
| 1067 | + @Override |
| 1068 | + public void remove() { |
| 1069 | + this.iterator.remove(); |
| 1070 | + } |
| 1071 | + |
| 1072 | + @Override |
| 1073 | + public K next() { |
| 1074 | + return this.iterator.next().getKey(); |
| 1075 | + } |
| 1076 | + } |
| 1077 | + |
| 1078 | + /** |
| 1079 | + * Internal values collection implementation. |
| 1080 | + */ |
| 1081 | + private final class Values extends AbstractCollection<V> { |
| 1082 | + @Override |
| 1083 | + public Iterator<V> iterator() { |
| 1084 | + return new ValueIterator(); |
| 1085 | + } |
| 1086 | + |
| 1087 | + @Override |
| 1088 | + public int size() { |
| 1089 | + return ConcurrentReferenceHashMap.this.size(); |
| 1090 | + } |
| 1091 | + |
| 1092 | + @Override |
| 1093 | + public boolean isEmpty() { |
| 1094 | + return ConcurrentReferenceHashMap.this.isEmpty(); |
| 1095 | + } |
| 1096 | + |
| 1097 | + @Override |
| 1098 | + public void clear() { |
| 1099 | + ConcurrentReferenceHashMap.this.clear(); |
| 1100 | + } |
| 1101 | + |
| 1102 | + @Override |
| 1103 | + public boolean contains(Object v) { |
| 1104 | + return ConcurrentReferenceHashMap.this.containsValue(v); |
| 1105 | + } |
| 1106 | + |
| 1107 | + @Override |
| 1108 | + public Spliterator<V> spliterator() { |
| 1109 | + return Spliterators.spliterator(this, Spliterator.CONCURRENT); |
| 1110 | + } |
979 | 1111 | } |
980 | 1112 |
|
| 1113 | + /** |
| 1114 | + * Internal value iterator implementation. |
| 1115 | + */ |
| 1116 | + private final class ValueIterator implements Iterator<V> { |
| 1117 | + |
| 1118 | + private final Iterator<Map.Entry<K, V>> iterator = entrySet().iterator(); |
| 1119 | + |
| 1120 | + @Override |
| 1121 | + public boolean hasNext() { |
| 1122 | + return this.iterator.hasNext(); |
| 1123 | + } |
| 1124 | + |
| 1125 | + @Override |
| 1126 | + public void remove() { |
| 1127 | + this.iterator.remove(); |
| 1128 | + } |
| 1129 | + |
| 1130 | + @Override |
| 1131 | + public V next() { |
| 1132 | + return this.iterator.next().getValue(); |
| 1133 | + } |
| 1134 | + } |
981 | 1135 |
|
982 | 1136 | /** |
983 | 1137 | * Internal entry iterator implementation. |
984 | 1138 | */ |
985 | | - private class EntryIterator implements Iterator<Map.Entry<K, V>> { |
| 1139 | + private final class EntryIterator implements Iterator<Map.Entry<K, V>> { |
986 | 1140 |
|
987 | 1141 | private int segmentIndex; |
988 | 1142 |
|
|
0 commit comments