- 浏览: 980117 次
文章分类
- 全部博客 (428)
- Hadoop (2)
- HBase (1)
- ELK (1)
- ActiveMQ (13)
- Kafka (5)
- Redis (14)
- Dubbo (1)
- Memcached (5)
- Netty (56)
- Mina (34)
- NIO (51)
- JUC (53)
- Spring (13)
- Mybatis (17)
- MySQL (21)
- JDBC (12)
- C3P0 (5)
- Tomcat (13)
- SLF4J-log4j (9)
- P6Spy (4)
- Quartz (12)
- Zabbix (7)
- JAVA (9)
- Linux (15)
- HTML (9)
- Lucene (0)
- JS (2)
- WebService (1)
- Maven (4)
- Oracle&MSSQL (14)
- iText (11)
- Development Tools (8)
- UTILS (4)
- LIFE (8)
最新评论
-
Donald_Draper:
Donald_Draper 写道刘落落cici 写道能给我发一 ...
DatagramChannelImpl 解析三(多播) -
Donald_Draper:
刘落落cici 写道能给我发一份这个类的源码吗Datagram ...
DatagramChannelImpl 解析三(多播) -
lyfyouyun:
请问楼主,执行消息发送的时候,报错:Transport sch ...
ActiveMQ连接工厂、连接详解 -
ezlhq:
关于 PollArrayWrapper 状态含义猜测:参考 S ...
WindowsSelectorImpl解析一(FdMap,PollArrayWrapper) -
flyfeifei66:
打算使用xmemcache作为memcache的客户端,由于x ...
Memcached分布式客户端(Xmemcached)
HashMap详解:http://donald-draper.iteye.com/blog/2361702
ConcurrentMap介绍:http://donald-draper.iteye.com/blog/2361719
ConcurrentHashMap解析-Segment:http://donald-draper.iteye.com/blog/2363200
前言:
上一篇文章我们看了一下ConcurrentHashMap的Segment,今天来看ConcurrentHashMap的相关操作。先回顾一下上一篇的内容:
ConcurrentHashMap是线程安全的,可并发访问,不允许key或value的值为null,默认的容量为16,负载因子为0.75,并发访问量为16。ConcurrentHashMap中有一个Segment数组,默认数组大小为16,Segment中有一个HashEntry数组类似于HashMap中的table,Segment继承了可重入锁ReentrantLock,Segment的修改其hash table的操作都要使用lock。Segment的put操作,首先尝试获取锁,如果获取锁失败,则Key在片段hash table中的索引,遍历索引对应的Hash Entry链,如找不到key对应HashEntry,则创建一个HashEntry,这都是在尝试次数小于最大尝试次数MAX_SCAN_RETRIES情况下,MAX_SCAN_RETRIES默认为2。这样做的目的是为确保,进行put操作时,仍持有锁。然后定位key在片段table中的索引,并放在链头,如果实际size达到临界条件,则重新hash,创建2倍原始容量的hash table,重新建立hash table。Segment的remove操作,首先尝试获取锁失败,则继续尝试获取锁,在获取锁的过程中,定位key在片段table的HashEntry链表索引,遍历链表,如果找到对应HashEntry,则移除,如果尝试次数超过最大尝试次数,则lock,则遍历链表,找到对应的HashEntry,则移除。replace与remove的基本思路相同,唯一的区别是,当替换值时,修改计数要自增1。put,remove和replace操作是锁住片段table中,key对应的索引HashEntry链表,而Clear为锁住整个table。ConcurrentHashMap通过将所有HashEntry分散在不同的Segment,及锁机制实现了并发访问。
来看HashMap的put操作
putIfAbsent与put操作的区别为onlyIfAbsent为true,存在返回旧值,否则放到对应
的Segment的hash table中。
Remove操作:
再看repalce
从上面分析的put,remove,replace操作来看,基本思路相同,先定位定位Segment,
再将操作委托给Segment相应的操作。
再看get操作
//再看判断是包含key
思路与get操作类似;
判断是否为空
获取size
clear操作
ConCurrentHashMap实现ConCurrentMap和HashMap方法基本看完,我们再来看key,value,entrySet视图。
//EntrySet视图
//HashEntry Set集合类
从EntrySet的所有操作依附于ConcurrentHashMap
再来看EntryIterator
再来看HashIterator
//HashIterator
//KeyIterator
//ValueIterator
//KeySet
//Key视图
//Values
//value视图
总结:
put,remove,replace操作来看,基本思路相同,先定位定位Segment,
再将操作委托给Segment相应的操作。get操作是先定位定位Segment,再遍历key对应的HashEntry链表,找到,则返回值。视图基本思路为定位片段,在定位片段的hash table的Hash Entry链,遍历完当前片段,再遍历下一个片段的Hash table。
ConcurrentMap介绍:http://donald-draper.iteye.com/blog/2361719
ConcurrentHashMap解析-Segment:http://donald-draper.iteye.com/blog/2363200
前言:
上一篇文章我们看了一下ConcurrentHashMap的Segment,今天来看ConcurrentHashMap的相关操作。先回顾一下上一篇的内容:
ConcurrentHashMap是线程安全的,可并发访问,不允许key或value的值为null,默认的容量为16,负载因子为0.75,并发访问量为16。ConcurrentHashMap中有一个Segment数组,默认数组大小为16,Segment中有一个HashEntry数组类似于HashMap中的table,Segment继承了可重入锁ReentrantLock,Segment的修改其hash table的操作都要使用lock。Segment的put操作,首先尝试获取锁,如果获取锁失败,则Key在片段hash table中的索引,遍历索引对应的Hash Entry链,如找不到key对应HashEntry,则创建一个HashEntry,这都是在尝试次数小于最大尝试次数MAX_SCAN_RETRIES情况下,MAX_SCAN_RETRIES默认为2。这样做的目的是为确保,进行put操作时,仍持有锁。然后定位key在片段table中的索引,并放在链头,如果实际size达到临界条件,则重新hash,创建2倍原始容量的hash table,重新建立hash table。Segment的remove操作,首先尝试获取锁失败,则继续尝试获取锁,在获取锁的过程中,定位key在片段table的HashEntry链表索引,遍历链表,如果找到对应HashEntry,则移除,如果尝试次数超过最大尝试次数,则lock,则遍历链表,找到对应的HashEntry,则移除。replace与remove的基本思路相同,唯一的区别是,当替换值时,修改计数要自增1。put,remove和replace操作是锁住片段table中,key对应的索引HashEntry链表,而Clear为锁住整个table。ConcurrentHashMap通过将所有HashEntry分散在不同的Segment,及锁机制实现了并发访问。
来看HashMap的put操作
/** * Maps the specified key to the specified value in this table. * Neither the key nor the value can be null. * * <p> The value can be retrieved by calling the <tt>get</tt> method * with a key that is equal to the original key. * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with <tt>key</tt>, or * <tt>null</tt> if there was no mapping for <tt>key</tt> * @throws NullPointerException if the specified key or value is null */ @SuppressWarnings("unchecked") public V put(K key, V value) { Segment<K,V> s; if (value == null) throw new NullPointerException(); //获取key的hash值,定位Segment, int hash = hash(key); int j = (hash >>> segmentShift) & segmentMask; if ((s = (Segment<K,V>)UNSAFE.getObject // nonvolatile; recheck (segments, (j << SSHIFT) + SBASE)) == null) // in ensureSegment //确保片段索引对应的Segment存在,不存在则创建 s = ensureSegment(j); //调用Segment的put操作,onlyIfAbsent为false,存在,则替换 return s.put(key, hash, value, false); } /** * Returns the segment for the given index, creating it and * recording in segment table (via CAS) if not already present. * * @param k the index * @return the segment */ //返回数组segment,指定索引的segment,如果不存在,则创建一个 @SuppressWarnings("unchecked") private Segment<K,V> ensureSegment(int k) { final Segment<K,V>[] ss = this.segments; long u = (k << SSHIFT) + SBASE; // raw offset Segment<K,V> seg; if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) { Segment<K,V> proto = ss[0]; // use segment 0 as prototype int cap = proto.table.length; float lf = proto.loadFactor; int threshold = (int)(cap * lf); HashEntry<K,V>[] tab = (HashEntry<K,V>[])new HashEntry[cap]; if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) { // recheck Segment<K,V> s = new Segment<K,V>(lf, threshold, tab); while ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) { if (UNSAFE.compareAndSwapObject(ss, u, null, seg = s)) break; } } } return seg; } /** * {@inheritDoc} * * @return the previous value associated with the specified key, * or <tt>null</tt> if there was no mapping for the key * @throws NullPointerException if the specified key or value is null */ 如果Map不包含对应的Key则,执行put的操作,否则返回旧值 @SuppressWarnings("unchecked") public V putIfAbsent(K key, V value) { Segment<K,V> s; if (value == null) throw new NullPointerException(); int hash = hash(key); int j = (hash >>> segmentShift) & segmentMask; if ((s = (Segment<K,V>)UNSAFE.getObject (segments, (j << SSHIFT) + SBASE)) == null) s = ensureSegment(j); return s.put(key, hash, value, true); }
putIfAbsent与put操作的区别为onlyIfAbsent为true,存在返回旧值,否则放到对应
的Segment的hash table中。
/** * Creates a new map with the same mappings as the given map. * The map is created with a capacity of 1.5 times the number * of mappings in the given map or 16 (whichever is greater), * and a default load factor (0.75) and concurrencyLevel (16). * * @param m the map */ 创建一个与参数Map相同HashEntry的Map public ConcurrentHashMap(Map<? extends K, ? extends V> m) { this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL); //委托给putAll putAll(m); } /** * Copies all of the mappings from the specified map to this one. * These mappings replace any mappings that this map had for any of the * keys currently in the specified map. * * @param m mappings to be stored in this map */ public void putAll(Map<? extends K, ? extends V> m) { 遍历HashEntry,放到新的Map中 for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) put(e.getKey(), e.getValue()); }
Remove操作:
/** * Removes the key (and its corresponding value) from this map. * This method does nothing if the key is not in the map. * * @param key the key that needs to be removed * @return the previous value associated with <tt>key</tt>, or * <tt>null</tt> if there was no mapping for <tt>key</tt> * @throws NullPointerException if the specified key is null */ public V remove(Object key) { int hash = hash(key); //定位片段 Segment<K,V> s = segmentForHash(hash); //委托给Segment的remove操作 return s == null ? null : s.remove(key, hash, null); } /** * Get the segment for the given hash */ //根据hash值定位片段Segment @SuppressWarnings("unchecked") private Segment<K,V> segmentForHash(int h) { long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE; return (Segment<K,V>) UNSAFE.getObjectVolatile(segments, u); } /** * {@inheritDoc} * * @throws NullPointerException if the specified key is null */ public boolean remove(Object key, Object value) { int hash = hash(key); Segment<K,V> s; return value != null && (s = segmentForHash(hash)) != null && s.remove(key, hash, value) != null; }
再看repalce
/** * {@inheritDoc} * * @throws NullPointerException if any of the arguments are null */ public boolean replace(K key, V oldValue, V newValue) { int hash = hash(key); if (oldValue == null || newValue == null) throw new NullPointerException(); Segment<K,V> s = segmentForHash(hash); return s != null && s.replace(key, hash, oldValue, newValue); } /** * {@inheritDoc} * * @return the previous value associated with the specified key, * or <tt>null</tt> if there was no mapping for the key * @throws NullPointerException if the specified key or value is null */ public V replace(K key, V value) { int hash = hash(key); if (value == null) throw new NullPointerException(); //定位Segment,委托给Segment Segment<K,V> s = segmentForHash(hash); return s == null ? null : s.replace(key, hash, value); }
从上面分析的put,remove,replace操作来看,基本思路相同,先定位定位Segment,
再将操作委托给Segment相应的操作。
再看get操作
public V get(Object key) { Segment<K,V> s; // manually integrate access methods to reduce overhead HashEntry<K,V>[] tab; int h = hash(key); //定位Segment long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE; if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null && (tab = s.table) != null) { //遍历key对应的HashEntry链表,找到,则返回值 for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE); e != null; e = e.next) { K k; if ((k = e.key) == key || (e.hash == h && key.equals(k))) return e.value; } } return null; }
//再看判断是包含key
public boolean containsKey(Object key) { Segment<K,V> s; // same as get() except no need for volatile value read HashEntry<K,V>[] tab; int h = hash(key); long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE; if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null && (tab = s.table) != null) { for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE); e != null; e = e.next) { K k; if ((k = e.key) == key || (e.hash == h && key.equals(k))) return true; } } return false; }
思路与get操作类似;
public boolean contains(Object value) { //委托给containsValue return containsValue(value); } /** * Returns <tt>true</tt> if this map maps one or more keys to the * specified value. Note: This method requires a full internal * traversal of the hash table, and so is much slower than * method <tt>containsKey</tt>. * containsValue需要遍历内部的所有片段的Hash table,所以速度是非常慢的 * @param value value whose presence in this map is to be tested * @return <tt>true</tt> if this map maps one or more keys to the * specified value * @throws NullPointerException if the specified value is null */ public boolean containsValue(Object value) { // Same idea as size() if (value == null) throw new NullPointerException(); final Segment<K,V>[] segments = this.segments; boolean found = false; long last = 0; int retries = -1; try { outer: for (;;) { if (retries++ == RETRIES_BEFORE_LOCK) { for (int j = 0; j < segments.length; ++j) //如果尝试次数为RETRIES_BEFORE_LOCK,则锁住所有片段 ensureSegment(j).lock(); // force creation } long hashSum = 0L; int sum = 0; //遍历所有片段的hash table的Hash Entry链表 for (int j = 0; j < segments.length; ++j) { HashEntry<K,V>[] tab; Segment<K,V> seg = segmentAt(segments, j); if (seg != null && (tab = seg.table) != null) { for (int i = 0 ; i < tab.length; i++) { HashEntry<K,V> e; for (e = entryAt(tab, i); e != null; e = e.next) { V v = e.value; if (v != null && value.equals(v)) { found = true; break outer; } } } sum += seg.modCount; } } if (retries > 0 && sum == last) break; last = sum; } } finally { if (retries > RETRIES_BEFORE_LOCK) { for (int j = 0; j < segments.length; ++j) segmentAt(segments, j).unlock(); } } return found; }
判断是否为空
/** * Returns <tt>true</tt> if this map contains no key-value mappings. * * @return <tt>true</tt> if this map contains no key-value mappings */ public boolean isEmpty() { /* * Sum per-segment modCounts to avoid mis-reporting when * elements are concurrently added and removed in one segment * while checking another, in which case the table was never * actually empty at any point. (The sum ensures accuracy up * through at least 1<<31 per-segment modifications before * recheck.) Methods size() and containsValue() use similar * constructions for stability checks. */ long sum = 0L; final Segment<K,V>[] segments = this.segments; //遍历判断,如果片段的size,不为null,则返回false for (int j = 0; j < segments.length; ++j) { Segment<K,V> seg = segmentAt(segments, j); if (seg != null) { if (seg.count != 0) return false; sum += seg.modCount; } } //利用Segment的modCount重新检查,以防遍历片段的时候,有修改操作 if (sum != 0L) { // recheck unless no modifications for (int j = 0; j < segments.length; ++j) { Segment<K,V> seg = segmentAt(segments, j); if (seg != null) { if (seg.count != 0) return false; sum -= seg.modCount; } } if (sum != 0L) return false; } return true; }
获取size
/** * Returns the number of key-value mappings in this map. If the * map contains more than <tt>Integer.MAX_VALUE</tt> elements, returns * <tt>Integer.MAX_VALUE</tt>. * * @return the number of key-value mappings in this map */ public int size() { // Try a few times to get accurate count. On failure due to // continuous async changes in table, resort to locking. final Segment<K,V>[] segments = this.segments; int size; boolean overflow; // true if size overflows 32 bits long sum; // sum of modCounts long last = 0L; // previous sum int retries = -1; // first iteration isn't retry try { for (;;) { if (retries++ == RETRIES_BEFORE_LOCK) { for (int j = 0; j < segments.length; ++j) ensureSegment(j).lock(); // force creation } sum = 0L; size = 0; overflow = false; //遍历片段,获取片段size之和,如果超过Integer.MAX_VALUE,则返回最大值。 for (int j = 0; j < segments.length; ++j) { Segment<K,V> seg = segmentAt(segments, j); if (seg != null) { sum += seg.modCount; int c = seg.count; if (c < 0 || (size += c) < 0) overflow = true; } } if (sum == last) break; last = sum; } } finally { if (retries > RETRIES_BEFORE_LOCK) { for (int j = 0; j < segments.length; ++j) segmentAt(segments, j).unlock(); } } return overflow ? Integer.MAX_VALUE : size; }
clear操作
/** * Removes all of the mappings from this map. */ public void clear() { final Segment<K,V>[] segments = this.segments; //遍历片段,clear所有片段 for (int j = 0; j < segments.length; ++j) { Segment<K,V> s = segmentAt(segments, j); if (s != null) s.clear(); } }
ConCurrentHashMap实现ConCurrentMap和HashMap方法基本看完,我们再来看key,value,entrySet视图。
//EntrySet视图
public Set<Map.Entry<K,V>> entrySet() { Set<Map.Entry<K,V>> es = entrySet; return (es != null) ? es : (entrySet = new EntrySet()); }
//HashEntry Set集合类
final class EntrySet extends AbstractSet<Map.Entry<K,V>> { public Iterator<Map.Entry<K,V>> iterator() { return new EntryIterator(); } public boolean contains(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<?,?> e = (Map.Entry<?,?>)o; V v = ConcurrentHashMap.this.get(e.getKey()); return v != null && v.equals(e.getValue()); } public boolean remove(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<?,?> e = (Map.Entry<?,?>)o; return ConcurrentHashMap.this.remove(e.getKey(), e.getValue()); } public int size() { return ConcurrentHashMap.this.size(); } public boolean isEmpty() { return ConcurrentHashMap.this.isEmpty(); } public void clear() { ConcurrentHashMap.this.clear(); } }
从EntrySet的所有操作依附于ConcurrentHashMap
再来看EntryIterator
final class EntryIterator extends HashIterator implements Iterator<Entry<K,V>> { public Map.Entry<K,V> next() { HashEntry<K,V> e = super.nextEntry(); //next返回WriteThroughEntry return new WriteThroughEntry(e.key, e.value); } } /** * Custom Entry class used by EntryIterator.next(), that relays * setValue changes to the underlying map. */ 包装EntryIterator的next元素为可修改值的WriteThroughEntry final class WriteThroughEntry extends AbstractMap.SimpleEntry<K,V> { WriteThroughEntry(K k, V v) { super(k,v); } /** * Set our entry's value and write through to the map. The * value to return is somewhat arbitrary here. Since a * WriteThroughEntry does not necessarily track asynchronous * changes, the most recent "previous" value could be * different from what we return (or could even have been * removed in which case the put will re-establish). We do not * and cannot guarantee more. */ public V setValue(V value) { if (value == null) throw new NullPointerException(); V v = super.setValue(value); ConcurrentHashMap.this.put(getKey(), value); return v; } }
再来看HashIterator
//HashIterator
abstract class HashIterator { int nextSegmentIndex;//next片段索引 int nextTableIndex;//next片段table索引 HashEntry<K,V>[] currentTable;当前片段 HashEntry<K, V> nextEntry;//链表HashEntry HashEntry<K, V> lastReturned; HashIterator() { nextSegmentIndex = segments.length - 1; nextTableIndex = -1; advance(); } /** * Set nextEntry to first node of next non-empty table * (in backwards order, to simplify checks). */ //循环遍历片段及片段table,返回不为null的hash table的hashEntry的第一个Node为nextEntry final void advance() { for (;;) { if (nextTableIndex >= 0) { //如果hash table的索引大于0,则定位当前table,索引对应的HashEntry链表 if ((nextEntry = entryAt(currentTable, nextTableIndex--)) != null) break; } else if (nextSegmentIndex >= 0) { //定位片段 Segment<K,V> seg = segmentAt(segments, nextSegmentIndex--); //获取当前片段的hash table if (seg != null && (currentTable = seg.table) != null) nextTableIndex = currentTable.length - 1; } else break; } } final HashEntry<K,V> nextEntry() { HashEntry<K,V> e = nextEntry; if (e == null) throw new NoSuchElementException(); lastReturned = e; // cannot assign until after null check if ((nextEntry = e.next) == null) advance(); return e; } public final boolean hasNext() { return nextEntry != null; } public final boolean hasMoreElements() { return nextEntry != null; } //移除操作 public final void remove() { if (lastReturned == null) throw new IllegalStateException(); ConcurrentHashMap.this.remove(lastReturned.key); lastReturned = null; } }
//KeyIterator
final class KeyIterator extends HashIterator implements Iterator<K>, Enumeration<K> { public final K next() { return super.nextEntry().key; } public final K nextElement() { return super.nextEntry().key; } }
//ValueIterator
final class ValueIterator extends HashIterator implements Iterator<V>, Enumeration<V> { public final V next() { return super.nextEntry().value; } public final V nextElement() { return super.nextEntry().value; } }
//KeySet
final class KeySet extends AbstractSet<K> { public Iterator<K> iterator() { return new KeyIterator(); } public int size() { return ConcurrentHashMap.this.size(); } public boolean isEmpty() { return ConcurrentHashMap.this.isEmpty(); } public boolean contains(Object o) { return ConcurrentHashMap.this.containsKey(o); } public boolean remove(Object o) { return ConcurrentHashMap.this.remove(o) != null; } public void clear() { ConcurrentHashMap.this.clear(); } }
//Key视图
public Set<K> keySet() { Set<K> ks = keySet; return (ks != null) ? ks : (keySet = new KeySet()); }
//Values
final class Values extends AbstractCollection<V> { public Iterator<V> iterator() { return new ValueIterator(); } public int size() { return ConcurrentHashMap.this.size(); } public boolean isEmpty() { return ConcurrentHashMap.this.isEmpty(); } public boolean contains(Object o) { return ConcurrentHashMap.this.containsValue(o); } public void clear() { ConcurrentHashMap.this.clear(); } }
//value视图
public Collection<V> values() { Collection<V> vs = values; return (vs != null) ? vs : (values = new Values()); }
/** * Returns an enumeration of the keys in this table. * * @return an enumeration of the keys in this table * @see #keySet() */ public Enumeration<K> keys() { return new KeyIterator(); } /** * Returns an enumeration of the values in this table. * * @return an enumeration of the values in this table * @see #values() */ public Enumeration<V> elements() { return new ValueIterator(); }
总结:
put,remove,replace操作来看,基本思路相同,先定位定位Segment,
再将操作委托给Segment相应的操作。get操作是先定位定位Segment,再遍历key对应的HashEntry链表,找到,则返回值。视图基本思路为定位片段,在定位片段的hash table的Hash Entry链,遍历完当前片段,再遍历下一个片段的Hash table。
发表评论
-
Executors解析
2017-04-07 14:38 1244ThreadPoolExecutor解析一(核心线程池数量、线 ... -
ScheduledThreadPoolExecutor解析三(关闭线程池)
2017-04-06 20:52 4450ScheduledThreadPoolExecutor解析一( ... -
ScheduledThreadPoolExecutor解析二(任务调度)
2017-04-06 12:56 2116ScheduledThreadPoolExecutor解析一( ... -
ScheduledThreadPoolExecutor解析一(调度任务,任务队列)
2017-04-04 22:59 4986Executor接口的定义:http://donald-dra ... -
ThreadPoolExecutor解析四(线程池关闭)
2017-04-03 23:02 9096Executor接口的定义:http: ... -
ThreadPoolExecutor解析三(线程池执行提交任务)
2017-04-03 12:06 6078Executor接口的定义:http://donald-dra ... -
ThreadPoolExecutor解析二(线程工厂、工作线程,拒绝策略等)
2017-04-01 17:12 3036Executor接口的定义:http://donald-dra ... -
ThreadPoolExecutor解析一(核心线程池数量、线程池状态等)
2017-03-31 22:01 20513Executor接口的定义:http://donald-dra ... -
ScheduledExecutorService接口定义
2017-03-29 12:53 1501Executor接口的定义:http://donald-dra ... -
AbstractExecutorService解析
2017-03-29 08:27 1071Executor接口的定义:http: ... -
ExecutorCompletionService解析
2017-03-28 14:27 1586Executor接口的定义:http://donald-dra ... -
CompletionService接口定义
2017-03-28 12:39 1061Executor接口的定义:http://donald-dra ... -
FutureTask解析
2017-03-27 12:59 1324package java.util.concurrent; ... -
Future接口定义
2017-03-26 09:40 1190/* * Written by Doug Lea with ... -
ExecutorService接口定义
2017-03-25 22:14 1158Executor接口的定义:http://donald-dra ... -
Executor接口的定义
2017-03-24 23:24 1671package java.util.concurrent; ... -
简单测试线程池拒绝执行任务策略
2017-03-24 22:37 2023线程池多余任务的拒绝执行策略有四中,分别是直接丢弃任务Disc ... -
JAVA集合类简单综述
2017-03-23 22:51 920Queue接口定义:http://donald-draper. ... -
DelayQueue解析
2017-03-23 11:00 1732Queue接口定义:http://donald-draper. ... -
SynchronousQueue解析下-TransferQueue
2017-03-22 22:20 2133Queue接口定义:http://donald-draper. ...
相关推荐
本篇文章将深入解析这两种数据结构的内部实现,帮助读者理解它们的工作原理。 HashMap是Java中最常用的哈希表实现,它通过哈希函数快速定位键值对,并通过链表解决哈希冲突。在Java 7中,HashMap的内部结构主要由一...
Java编程技巧典型案例解析 在Java编程领域,掌握高效、实用的编程技巧对于提升代码质量、优化性能以及提高开发效率至关重要。本资料集旨在通过一系列典型示例,深入剖析Java编程中的常见问题及其解决策略,帮助...
`size()`方法只是一个估计值,通过` ConcurrentHashMap `的`size()`方法返回,而`clear()`方法则是通过调用`ConcurrentHashMap`的`clear()`实现,但这并不能立即清除所有元素,而是会在后续的操作中逐渐清理。...
针对这一主题,我们将深入解析其中涉及的Java知识点,帮助你更好地理解和准备类似的面试或笔试。 首先,Java作为客户端开发的基础语言,其核心概念是不可或缺的。这包括但不限于类与对象、封装、继承和多态等面向...
通过解析,Canal能够理解数据库表结构和变更内容,为后续的数据处理提供基础。 三、数据监听 数据监听是Canal的另一个重要功能。通过Canal Server,可以实时监听数据库的变更事件,并将这些事件推送给订阅者。这...
### BAT互联网Java面试题汇总知识点解析 #### 一、HashMap的底层原理及冲突解决机制 - **HashMap** 是一种常用的数据结构,在Java中用于存储Key-Value键值对。其核心是一个数组`table`,数组中的每个元素是一个...
- **并发API**:扩展了Java并发工具集,包括`ForkJoinPool`和`ConcurrentHashMap`的新特性等。 - **JMX API**:增强了Java管理扩展(JMX)的功能,便于远程管理和监控Java应用程序。 #### 三、深入理解Java JDK 1.7...
1. **连接初始化**:DruidDataSource在初始化时,会根据配置信息创建一定数量的初始连接,并在后续运行中根据连接池策略动态调整连接数量。 2. **连接生命周期管理**:Druid使用了独创的“连接有效性检查”机制,...
在图片缓存中,`ConcurrentHashMap`可能被用来存储内存缓存未命中的图片URL,以便后续写入到磁盘。由于磁盘操作相对耗时,所以采用线程安全的数据结构可以保证多线程环境下的安全性,避免数据冲突。 3. **本地存储...
- 选项 **C**:分区段加锁(例如使用 `ConcurrentHashMap` 的设计思想),可以有效地减少锁的竞争,提高并发性能,尤其是在多核处理器环境下更为有效。 - 选项 **D**:实际上是可以做到的,排除。 - **结论**:...
方法中,定时器ID(`timerId`)被设置,然后返回这个ID以便后续使用。然而,给出的代码中并没有真正实现定时器的启动,例如通过线程来执行定时任务。实际上,你可能需要使用 `ScheduledExecutorService` 或 `java....
- `private Map, Integer> data`: 使用`ConcurrentHashMap`存储每个线程当前的下载位置。 - `private int block`: 每个线程负责下载的数据块大小。 - `private String downloadUrl`: 下载文件的URL字符串形式。 ...
- **ConcurrentHashMap**:在JDK 7中,ConcurrentHashMap提供了更高的并发性和更少的锁竞争,提升了多线程环境下的性能。 5. **新的API和库**: - **NIO.2**:引入了新的文件系统API,提供异步I/O操作,增强了对...
其中,`java.util.concurrent`包新增了线程安全的集合实现,如`ConcurrentHashMap`,对于多线程环境下的数据共享非常有用。 3. **IO流** `java.io`包中的InputStream和OutputStream是处理字节流的基本接口,而...
同时,随着Java 8及后续版本的发布,函数式编程、Lambda表达式、Stream API等新特性也会有详尽的介绍。 对于大型项目,遵循一定的编码规范和最佳实践至关重要。《Java开发手册---泰山版》将包含命名规范、注释规范...
线程安全的集合类(如ConcurrentHashMap)可确保在多线程环境下数据的一致性。 6. IP代理池:为了避免频繁访问同一网站导致IP被封,网络爬虫可以使用IP代理池,定期更换IP进行请求。Java可以调用第三方API来获取...
在并发编程方面,《Core Java 9th Volume II》详细解析了多线程和并发控制,如线程的创建与同步、锁、条件变量、并发容器(如ConcurrentHashMap)以及异步编程模型。这部分内容对于构建高并发、高性能的应用至关重要...
最后,随着Java 8及后续版本的发布,函数式编程、Lambda表达式、Stream API等新特性也可能会被详细解析,这些让Java变得更加简洁和高效。 总之,“java高手的文章合集”是一个全面涵盖Java基础知识与进阶技术的资源...
3. 并发编程:线程安全、锁机制(synchronized、Lock)、并发容器(ConcurrentHashMap、CopyOnWriteArrayList)、线程池(ThreadPoolExecutor)。 4. Spring框架:IoC/DI原理、AOP实现、Spring Boot、Spring Cloud...
13. **XML解析**:DOM和SAX两种解析方式,读取、写入和修改XML文件。 14. **Lambda表达式和函数式接口**:Java 8引入的新特性,简化匿名内部类,提高代码简洁性。 15. **并发编程**:原子类、并发工具类(如...