Source Code Cross Referenced for ConcurrentHashMap.java in  » Database-ORM » openjpa » org » apache » openjpa » lib » util » concurrent » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database ORM » openjpa » org.apache.openjpa.lib.util.concurrent 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Licensed to the Apache Software Foundation (ASF) under one
003:         * or more contributor license agreements.  See the NOTICE file
004:         * distributed with this work for additional information
005:         * regarding copyright ownership.  The ASF licenses this file
006:         * to you under the Apache License, Version 2.0 (the
007:         * "License"); you may not use this file except in compliance
008:         * with the License.  You may obtain a copy of the License at
009:         *
010:         * http://www.apache.org/licenses/LICENSE-2.0
011:         *
012:         * Unless required by applicable law or agreed to in writing,
013:         * software distributed under the License is distributed on an
014:         * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015:         * KIND, either express or implied.  See the License for the
016:         * specific language governing permissions and limitations
017:         * under the License.    
018:         */
019:        package org.apache.openjpa.lib.util.concurrent;
020:
021:        import java.io.IOException;
022:        import java.io.ObjectInputStream;
023:        import java.io.ObjectOutputStream;
024:        import java.io.Serializable;
025:        import java.util.AbstractCollection;
026:        import java.util.AbstractMap;
027:        import java.util.AbstractSet;
028:        import java.util.Collection;
029:        import java.util.Iterator;
030:        import java.util.Map;
031:        import java.util.NoSuchElementException;
032:        import java.util.Random;
033:        import java.util.Set;
034:
035:        import org.apache.openjpa.lib.util.SizedMap;
036:
037:        /**
038:         * This class implements a HashMap which has limited synchronization.
039:         * In particular mutators are generally synchronized while accessors
040:         * are generally not. Additionally the Iterators returned by this
041:         * class are not "fail-fast", but instead try to continue to iterate
042:         * over the data structure after changes have been made.
043:         * The synchronization semantics are built right in to the
044:         * implementation rather than using a delegating wrapper like the
045:         * other collection classes do because it wasn't clear to me that the
046:         * how the two should be seperated or that it would be useful to do
047:         * so. This can probably be a topic for further debate in the future.
048:         * This class is based heavily on the HashMap class in the Java
049:         * collections package.
050:         */
051:        public class ConcurrentHashMap extends AbstractMap implements 
052:                ConcurrentMap, SizedMap, Cloneable, Serializable {
053:
054:            /**
055:             * The default initial capacity - MUST be a power of two.
056:             */
057:            private static final int DEFAULT_INITIAL_CAPACITY = 16;
058:
059:            /**
060:             * The maximum capacity, used if a higher value is implicitly specified
061:             * by either of the constructors with arguments.
062:             * MUST be a power of two <= 1<<30.
063:             */
064:            private static final int MAXIMUM_CAPACITY = 1 << 30;
065:
066:            /**
067:             * The load fast used when none specified in constructor.
068:             */
069:            private static final float DEFAULT_LOAD_FACTOR = 0.75f;
070:
071:            /**
072:             * Cache of random numbers used in "random" methods, since generating them
073:             * is expensive. We hope each map changes enough between cycling through
074:             * this list that the overall effect is random enough.
075:             */
076:            static final double[] RANDOMS = new double[1000];
077:
078:            static {
079:                Random random = new Random();
080:                for (int i = 0; i < RANDOMS.length; i++)
081:                    RANDOMS[i] = random.nextDouble();
082:            }
083:
084:            /**
085:             * The table, resized as necessary. Length MUST Always be a power of two.
086:             */
087:            private transient Entry[] table;
088:
089:            /**
090:             * The number of key-value mappings contained in this identity hash map.
091:             */
092:            private transient int size;
093:
094:            /**
095:             * The next size value at which to resize(capacity * load factor).
096:             *
097:             * @serial
098:             */
099:            private int threshold;
100:
101:            /**
102:             * The load factor for the hash table.
103:             *
104:             * @serial
105:             */
106:            private final float loadFactor;
107:
108:            /**
109:             * Spread "random" removes and iteration.
110:             */
111:            private int randomEntry = 0;
112:
113:            /**
114:             * Maximum entries.
115:             */
116:            private int maxSize = Integer.MAX_VALUE;
117:
118:            /**
119:             * Constructs an empty <tt>ConcurrentHashMap</tt> with the specified initial
120:             * capacity and load factor.
121:             *
122:             * @param initialCapacity The initial capacity.
123:             * @param loadFactor The load factor.
124:             * @throws IllegalArgumentException if the initial capacity is negative
125:             * or the load factor is nonpositive.
126:             */
127:            public ConcurrentHashMap(int initialCapacity, float loadFactor) {
128:                if (initialCapacity < 0) {
129:                    throw new IllegalArgumentException(
130:                            "Illegal initial capacity: " + initialCapacity);
131:                }
132:                if (initialCapacity > MAXIMUM_CAPACITY)
133:                    initialCapacity = MAXIMUM_CAPACITY;
134:                if (loadFactor <= 0 || loadFactor > 1) {
135:                    throw new IllegalArgumentException("Illegal load factor: "
136:                            + loadFactor);
137:                }
138:
139:                // Find a power of 2 >= initialCapacity
140:                int capacity = 1;
141:                while (capacity < initialCapacity)
142:                    capacity <<= 1;
143:
144:                this .loadFactor = loadFactor;
145:                threshold = (int) (capacity * loadFactor);
146:                table = new Entry[capacity];
147:            }
148:
149:            /**
150:             * Constructs an empty <tt>ConcurrentHashMap</tt> with the specified initial
151:             * capacity and the default load factor(0.75).
152:             *
153:             * @param initialCapacity the initial capacity.
154:             * @throws IllegalArgumentException if the initial capacity is negative.
155:             */
156:            public ConcurrentHashMap(int initialCapacity) {
157:                this (initialCapacity, DEFAULT_LOAD_FACTOR);
158:            }
159:
160:            /**
161:             * Constructs an empty <tt>ConcurrentHashMap</tt> with the default initial
162:             * capacity(16) and the default load factor(0.75).
163:             */
164:            public ConcurrentHashMap() {
165:                this (DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
166:            }
167:
168:            /**
169:             * Constructs a new <tt>ConcurrentHashMap</tt> with the same mappings as the
170:             * specified <tt>Map</tt>. The <tt>ConcurrentHashMap</tt> is created with
171:             * default load factor(0.75) and an initial capacity sufficient to
172:             * hold the mappings in the specified <tt>Map</tt>.
173:             *
174:             * @param m the map whose mappings are to be placed in this map.
175:             * @throws NullPointerException if the specified map is null.
176:             */
177:            public ConcurrentHashMap(Map m) {
178:                this (Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
179:                        DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
180:                putAll(m);
181:            }
182:
183:            // internal utilities
184:
185:            /**
186:             * Value representing null keys inside tables.
187:             */
188:            private static final Object NULL_KEY = new Object();
189:
190:            /**
191:             * Returns internal representation for key. Use NULL_KEY if key is null.
192:             */
193:            private static Object maskNull(Object key) {
194:                return (key == null ? NULL_KEY : key);
195:            }
196:
197:            /**
198:             * Returns key represented by specified internal representation.
199:             */
200:            private static Object unmaskNull(Object key) {
201:                return (key == NULL_KEY ? null : key);
202:            }
203:
204:            /**
205:             * Returns a hash code for non-null Object x.
206:             */
207:            private static int hash(Object x) {
208:                int h = x.hashCode();
209:                return h - (h << 7); // i.e., -127 * h
210:            }
211:
212:            /**
213:             * Check for equality of non-null reference x and possibly-null y.
214:             */
215:            private static boolean eq(Object x, Object y) {
216:                return x == y || x.equals(y);
217:            }
218:
219:            /**
220:             * Returns the current capacity of backing table in this map.
221:             *
222:             * @return the current capacity of backing table in this map.
223:             */
224:            public final int capacity() {
225:                return table.length;
226:            }
227:
228:            /**
229:             * Returns the load factor for this map.
230:             *
231:             * @return the load factor for this map.
232:             */
233:            public final float loadFactor() {
234:                return loadFactor;
235:            }
236:
237:            public int getMaxSize() {
238:                return maxSize;
239:            }
240:
241:            public void setMaxSize(int maxSize) {
242:                this .maxSize = (maxSize < 0) ? Integer.MAX_VALUE : maxSize;
243:                if (this .maxSize != Integer.MAX_VALUE)
244:                    removeOverflow(this .maxSize);
245:            }
246:
247:            public boolean isFull() {
248:                return maxSize != Integer.MAX_VALUE && size() >= maxSize;
249:            }
250:
251:            public void overflowRemoved(Object key, Object value) {
252:            }
253:
254:            /**
255:             * Returns the number of key-value mappings in this map.
256:             *
257:             * @return the number of key-value mappings in this map.
258:             */
259:            public final int size() {
260:                return size;
261:            }
262:
263:            /**
264:             * Returns <tt>true</tt> if this map contains no key-value mappings.
265:             *
266:             * @return <tt>true</tt> if this map contains no key-value mappings.
267:             */
268:            public final boolean isEmpty() {
269:                return size == 0;
270:            }
271:
272:            /**
273:             * Returns the value to which the specified key is mapped in this identity
274:             * hash map, or <tt>null</tt> if the map contains no mapping for this key.
275:             * A return value of <tt>null</tt> does not <i>necessarily</i> indicate
276:             * that the map contains no mapping for the key; it is also possible that
277:             * the map explicitly maps the key to <tt>null</tt>. The
278:             * <tt>containsKey</tt> method may be used to distinguish these two cases.
279:             *
280:             * @param key the key whose associated value is to be returned.
281:             * @return the value to which this map maps the specified key, or
282:             * <tt>null</tt> if the map contains no mapping for this key.
283:             * @see #put(Object, Object)
284:             */
285:            public Object get(Object key) {
286:                Entry e = getEntry(key);
287:                return e == null ? null : e.value;
288:            }
289:
290:            /**
291:             * Returns <tt>true</tt> if this map contains a mapping for the
292:             * specified key.
293:             *
294:             * @param key The key whose presence in this map is to be tested
295:             * @return <tt>true</tt> if this map contains a mapping for the specified
296:             * key.
297:             */
298:            public final boolean containsKey(Object key) {
299:                return getEntry(key) != null;
300:            }
301:
302:            /**
303:             * Returns the entry associated with the specified key in the
304:             * ConcurrentHashMap. Returns null if the ConcurrentHashMap contains no
305:             * mapping for this key.
306:             */
307:            protected Entry getEntry(Object key) {
308:                Object k = maskNull(key);
309:                int hash = hash(k);
310:                Entry[] tab = table;
311:                for (Entry e = tab[hash & (tab.length - 1)]; e != null; e = e.next) {
312:                    if (e.hash == hash && eq(k, e.key))
313:                        return e;
314:                }
315:                return null;
316:            }
317:
318:            /**
319:             * Associates the specified value with the specified key in this map.
320:             * If the map previously contained a mapping for this key, the old
321:             * value is replaced.
322:             *
323:             * @param key key with which the specified value is to be associated.
324:             * @param value value to be associated with the specified key.
325:             * @return previous value associated with specified key, or <tt>null</tt>
326:             * if there was no mapping for key. A <tt>null</tt> return can
327:             * also indicate that the ConcurrentHashMap previously associated
328:             * <tt>null</tt> with the specified key.
329:             */
330:            public Object put(Object key, Object value) {
331:                Object k = maskNull(key);
332:                int hash = hash(k);
333:                synchronized (this ) {
334:                    int i = hash & (table.length - 1);
335:
336:                    for (Entry e = table[i]; e != null; e = e.next) {
337:                        if (e.hash == hash && eq(k, e.key)) {
338:                            Object oldValue = e.value;
339:                            e.value = value;
340:                            return oldValue;
341:                        }
342:                    }
343:
344:                    if (maxSize != Integer.MAX_VALUE)
345:                        removeOverflow(maxSize - 1);
346:                    table[i] = createEntry(hash, k, value, table[i]);
347:                    if (size++ >= threshold)
348:                        resize(2 * table.length);
349:                }
350:                return null;
351:            }
352:
353:            /**
354:             * Remove any entries equal to or over the max size.
355:             */
356:            private void removeOverflow(int maxSize) {
357:                while (size > maxSize) {
358:                    Map.Entry entry = removeRandom();
359:                    if (entry == null)
360:                        break;
361:                    overflowRemoved(entry.getKey(), entry.getValue());
362:                }
363:            }
364:
365:            public Object putIfAbsent(Object key, Object value) {
366:                Object k = maskNull(key);
367:                int hash = hash(k);
368:                synchronized (this ) {
369:                    int i = hash & (table.length - 1);
370:
371:                    for (Entry e = table[i]; e != null; e = e.next) {
372:                        if (e.hash == hash && eq(k, e.key)) {
373:                            return e.value;
374:                        }
375:                    }
376:
377:                    if (maxSize != Integer.MAX_VALUE)
378:                        removeOverflow(maxSize - 1);
379:                    table[i] = createEntry(hash, k, value, table[i]);
380:                    if (size++ >= threshold)
381:                        resize(2 * table.length);
382:                }
383:                return null;
384:            }
385:
386:            /**
387:             * Rehashes the contents of this map into a new <tt>ConcurrentHashMap</tt>
388:             * instance with a larger capacity. This method is called automatically when
389:             * the number of keys in this map exceeds its capacity and load factor.
390:             *
391:             * @param newCapacity the new capacity, MUST be a power of two.
392:             */
393:            private void resize(int newCapacity) {
394:                // assert(newCapacity & -newCapacity) == newCapacity; // power of 2
395:                Entry[] oldTable = table;
396:                int oldCapacity = oldTable.length;
397:
398:                // check if needed
399:                if (size < threshold || oldCapacity > newCapacity)
400:                    return;
401:
402:                Entry[] newTable = new Entry[newCapacity];
403:                int mask = newCapacity - 1;
404:                for (int i = oldCapacity; i-- > 0;) {
405:                    for (Entry e = oldTable[i]; e != null; e = e.next) {
406:                        Entry clone = (Entry) e.clone();
407:                        int j = clone.hash & mask;
408:                        clone.next = newTable[j];
409:                        newTable[j] = clone;
410:                    }
411:                }
412:                table = newTable;
413:                threshold = (int) (newCapacity * loadFactor);
414:            }
415:
416:            /**
417:             * Copies all of the mappings from the specified map to this map
418:             * These mappings will replace any mappings that
419:             * this map had for any of the keys currently in the specified map.
420:             *
421:             * @param t mappings to be stored in this map.
422:             * @throws NullPointerException if the specified map is null.
423:             */
424:            public final synchronized void putAll(Map t) {
425:                // Expand enough to hold t's elements without resizing.
426:                int n = t.size();
427:                if (n == 0)
428:                    return;
429:                if (n >= threshold) {
430:                    n = (int) (n / loadFactor + 1);
431:                    if (n > MAXIMUM_CAPACITY)
432:                        n = MAXIMUM_CAPACITY;
433:                    int capacity = table.length;
434:                    while (capacity < n)
435:                        capacity <<= 1;
436:                    resize(capacity);
437:                }
438:
439:                for (Iterator i = t.entrySet().iterator(); i.hasNext();) {
440:                    Map.Entry e = (Map.Entry) i.next();
441:                    put(e.getKey(), e.getValue());
442:                }
443:            }
444:
445:            /**
446:             * Removes the mapping for this key from this map if present.
447:             *
448:             * @param key key whose mapping is to be removed from the map.
449:             * @return previous value associated with specified key, or <tt>null</tt>
450:             * if there was no mapping for key. A <tt>null</tt> return can
451:             * also indicate that the map previously associated <tt>null</tt>
452:             * with the specified key.
453:             */
454:            public Object remove(Object key) {
455:                Entry e = removeEntryForKey(key);
456:                return (e == null ? e : e.value);
457:            }
458:
459:            /**
460:             * Removes and returns the entry associated with the specified key in the
461:             * ConcurrentHashMap. Returns null if the ConcurrentHashMap contains no
462:             * mapping for this key.
463:             */
464:            private Entry removeEntryForKey(Object key) {
465:                Object k = maskNull(key);
466:                int hash = hash(k);
467:                synchronized (this ) {
468:                    int i = hash & (table.length - 1);
469:                    Entry e = table[i];
470:
471:                    if (e == null)
472:                        return null;
473:                    if (e.hash == hash && eq(k, e.key)) {
474:                        size--;
475:                        table[i] = e.next;
476:                        return e;
477:                    }
478:
479:                    Entry prev = e;
480:                    for (e = e.next; e != null; prev = e, e = e.next) {
481:                        if (e.hash == hash && eq(k, e.key)) {
482:                            size--;
483:                            prev.next = e.next;
484:                            return e;
485:                        }
486:                    }
487:                }
488:                return null;
489:            }
490:
491:            /**
492:             * Special version of remove for EntrySet.
493:             */
494:            private Entry removeMapping(Object o) {
495:                if (!(o instanceof  Map.Entry))
496:                    return null;
497:
498:                Map.Entry entry = (Map.Entry) o;
499:                Object k = maskNull(entry.getKey());
500:                int hash = hash(k);
501:                synchronized (this ) {
502:                    int i = hash & (table.length - 1);
503:                    Entry e = table[i];
504:
505:                    if (e == null)
506:                        return null;
507:                    if (e.hash == hash && e.equals(entry)) {
508:                        size--;
509:                        table[i] = e.next;
510:                        return e;
511:                    }
512:
513:                    Entry prev = e;
514:                    for (e = e.next; e != null; prev = e, e = e.next) {
515:                        if (e.hash == hash && e.equals(entry)) {
516:                            size--;
517:                            prev.next = e.next;
518:                            return e;
519:                        }
520:                    }
521:                }
522:                return null;
523:            }
524:
525:            /**
526:             * Removes all mappings from this map.
527:             */
528:            public synchronized void clear() {
529:                table = new Entry[table.length];
530:                size = 0;
531:            }
532:
533:            /**
534:             * Return an arbitrary entry index.
535:             */
536:            private int randomEntryIndex() {
537:                if (randomEntry == RANDOMS.length)
538:                    randomEntry = 0;
539:                return (int) (RANDOMS[randomEntry++] * table.length);
540:            }
541:
542:            public Map.Entry removeRandom() {
543:                if (size == 0)
544:                    return null;
545:
546:                synchronized (this ) {
547:                    int random = randomEntryIndex();
548:                    int index = findEntry(random, random % 2 == 0, false);
549:                    if (index == -1)
550:                        return null;
551:                    Entry rem = table[index];
552:                    table[index] = rem.next;
553:                    size--;
554:                    return rem;
555:                }
556:            }
557:
558:            /**
559:             * Find the index of the entry nearest the given index, starting in the
560:             * given direction.
561:             */
562:            private int findEntry(int start, boolean forward,
563:                    boolean searchedOther) {
564:                if (forward) {
565:                    for (int i = start; i < table.length; i++)
566:                        if (table[i] != null)
567:                            return i;
568:                    return (searchedOther || start == 0) ? -1 : findEntry(
569:                            start - 1, false, true);
570:                } else {
571:                    for (int i = start; i >= 0; i--)
572:                        if (table[i] != null)
573:                            return i;
574:                    return (searchedOther || start == table.length - 1) ? -1
575:                            : findEntry(start + 1, true, true);
576:                }
577:            }
578:
579:            public Iterator randomEntryIterator() {
580:                // pass index so calculated before iterator refs table, in case table
581:                // gets replace with a larger one
582:                return new HashIterator(ENTRIES, randomEntryIndex());
583:            }
584:
585:            /**
586:             * Returns <tt>true</tt> if this map maps one or more keys to the
587:             * specified value.
588:             *
589:             * @param value value whose presence in this map is to be tested.
590:             * @return <tt>true</tt> if this map maps one or more keys to the
591:             * specified value.
592:             */
593:            public final boolean containsValue(Object value) {
594:                if (value == null)
595:                    return containsNullValue();
596:
597:                Entry tab[] = table;
598:                for (int i = 0; i < tab.length; i++) {
599:                    for (Entry e = tab[i]; e != null; e = e.next) {
600:                        if (value.equals(e.value))
601:                            return true;
602:                    }
603:                }
604:                return false;
605:            }
606:
607:            /**
608:             * Special-case code for containsValue with null argument
609:             */
610:            private boolean containsNullValue() {
611:                Entry tab[] = table;
612:                for (int i = 0; i < tab.length; i++) {
613:                    for (Entry e = tab[i]; e != null; e = e.next) {
614:                        if (e.value == null)
615:                            return true;
616:                    }
617:                }
618:                return false;
619:            }
620:
621:            /**
622:             * Returns a shallow copy of this <tt>ConcurrentHashMap</tt> instance: the
623:             * keys and values themselves are not cloned.
624:             *
625:             * @return a shallow copy of this map.
626:             */
627:            public final Object clone() {
628:                return new ConcurrentHashMap(this );
629:            }
630:
631:            protected Entry createEntry(int h, Object k, Object v, Entry n) {
632:                return new Entry(h, k, v, n);
633:            }
634:
635:            protected static class Entry implements  Map.Entry {
636:
637:                final Object key;
638:                Object value;
639:                final int hash;
640:                Entry next;
641:
642:                /**
643:                 * Create new entry.
644:                 */
645:                protected Entry(int h, Object k, Object v, Entry n) {
646:                    value = v;
647:                    next = n;
648:                    key = k;
649:                    hash = h;
650:                }
651:
652:                public Object getKey() {
653:                    return unmaskNull(key);
654:                }
655:
656:                public Object getValue() {
657:                    return value;
658:                }
659:
660:                public Object setValue(Object newValue) {
661:                    Object oldValue = value;
662:                    value = newValue;
663:                    return oldValue;
664:                }
665:
666:                public boolean equals(Object o) {
667:                    if (!(o instanceof  Map.Entry))
668:                        return false;
669:                    Map.Entry e = (Map.Entry) o;
670:                    Object k1 = getKey();
671:                    Object k2 = e.getKey();
672:                    if (k1 == k2 || (k1 != null && k1.equals(k2))) {
673:                        Object v1 = getValue();
674:                        Object v2 = e.getValue();
675:                        if (v1 == v2 || (v1 != null && v1.equals(v2)))
676:                            return true;
677:                    }
678:                    return false;
679:                }
680:
681:                public int hashCode() {
682:                    return (key == NULL_KEY ? 0 : key.hashCode())
683:                            ^ (value == null ? 0 : value.hashCode());
684:                }
685:
686:                public String toString() {
687:                    return getKey() + "=" + getValue();
688:                }
689:
690:                protected Object clone() {
691:                    // It is the callers responsibility to set the next field
692:                    // correctly.
693:                    return new Entry(hash, key, value, null);
694:                }
695:            }
696:
697:            // Types of Enumerations/Iterations
698:            private static final int KEYS = 0;
699:            private static final int VALUES = 1;
700:            private static final int ENTRIES = 2;
701:
702:            /**
703:             * Map iterator.
704:             */
705:            private class HashIterator implements  Iterator {
706:
707:                final Entry[] table = ConcurrentHashMap.this .table;
708:                final int type;
709:                int startIndex;
710:                int stopIndex = 0;
711:                int index;
712:                Entry entry = null;
713:                Entry lastReturned = null;
714:
715:                HashIterator(int type, int startIndex) {
716:                    this .type = type;
717:                    this .startIndex = startIndex;
718:                    index = startIndex;
719:                }
720:
721:                public boolean hasNext() {
722:                    if (entry != null) {
723:                        return true;
724:                    }
725:                    while (index >= stopIndex) {
726:                        if ((entry = table[index--]) != null) {
727:                            return true;
728:                        }
729:                    }
730:                    if (stopIndex == 0) {
731:                        index = table.length - 1;
732:                        stopIndex = startIndex + 1;
733:                        while (index >= stopIndex) {
734:                            if ((entry = table[index--]) != null) {
735:                                return true;
736:                            }
737:                        }
738:                    }
739:                    return false;
740:                }
741:
742:                public Object next() {
743:                    if (!hasNext())
744:                        throw new NoSuchElementException();
745:                    Entry e = lastReturned = entry;
746:                    entry = e.next;
747:                    return type == KEYS ? e.key
748:                            : (type == VALUES ? e.value : e);
749:                }
750:
751:                public void remove() {
752:                    if (lastReturned == null)
753:                        throw new IllegalStateException();
754:                    synchronized (ConcurrentHashMap.this ) {
755:                        Entry[] tab = ConcurrentHashMap.this .table;
756:                        int index = (lastReturned.hash & 0x7FFFFFFF)
757:                                % tab.length;
758:
759:                        for (Entry e = tab[index], prev = null; e != null; prev = e, e = e.next) {
760:                            if (e == lastReturned) {
761:                                if (prev == null)
762:                                    tab[index] = e.next;
763:                                else
764:                                    prev.next = e.next;
765:                                size--;
766:                                lastReturned = null;
767:                                return;
768:                            }
769:                        }
770:                        throw new Error("Iterated off table when doing remove");
771:                    }
772:                }
773:            }
774:
775:            // Views
776:
777:            private transient Set entrySet = null;
778:            private transient Set keySet = null;
779:            private transient Collection values = null;
780:
781:            /**
782:             * Returns a set view of the keys contained in this map. The set is
783:             * backed by the map, so changes to the map are reflected in the set, and
784:             * vice-versa. The set supports element removal, which removes the
785:             * corresponding mapping from this map, via the <tt>Iterator.remove</tt>,
786:             * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
787:             * <tt>clear</tt> operations. It does not support the <tt>add</tt> or
788:             * <tt>addAll</tt> operations.
789:             *
790:             * @return a set view of the keys contained in this map.
791:             */
792:            public final Set keySet() {
793:                Set ks = keySet;
794:                return (ks != null ? ks : (keySet = new KeySet()));
795:            }
796:
797:            private final class KeySet extends AbstractSet {
798:
799:                public Iterator iterator() {
800:                    return new HashIterator(KEYS, table.length - 1);
801:                }
802:
803:                public int size() {
804:                    return size;
805:                }
806:
807:                public boolean contains(Object o) {
808:                    return containsKey(o);
809:                }
810:
811:                public boolean remove(Object o) {
812:                    return ConcurrentHashMap.this .removeEntryForKey(o) != null;
813:                }
814:
815:                public void clear() {
816:                    ConcurrentHashMap.this .clear();
817:                }
818:            }
819:
820:            /**
821:             * Returns a collection view of the values contained in this map. The
822:             * collection is backed by the map, so changes to the map are reflected in
823:             * the collection, and vice-versa. The collection supports element
824:             * removal, which removes the corresponding mapping from this map, via the
825:             * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
826:             * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
827:             * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
828:             *
829:             * @return a collection view of the values contained in this map.
830:             */
831:            public final Collection values() {
832:                Collection vs = values;
833:                return (vs != null ? vs : (values = new Values()));
834:            }
835:
836:            private final class Values extends AbstractCollection {
837:
838:                public Iterator iterator() {
839:                    return new HashIterator(VALUES, table.length - 1);
840:                }
841:
842:                public int size() {
843:                    return size;
844:                }
845:
846:                public boolean contains(Object o) {
847:                    return containsValue(o);
848:                }
849:
850:                public void clear() {
851:                    ConcurrentHashMap.this .clear();
852:                }
853:            }
854:
855:            /**
856:             * Returns a collection view of the mappings contained in this map. Each
857:             * element in the returned collection is a <tt>Map.Entry</tt>. The
858:             * collection is backed by the map, so changes to the map are reflected in
859:             * the collection, and vice-versa. The collection supports element
860:             * removal, which removes the corresponding mapping from the map, via the
861:             * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
862:             * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
863:             * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
864:             *
865:             * @return a collection view of the mappings contained in this map.
866:             * @see Map.Entry
867:             */
868:            public final Set entrySet() {
869:                Set es = entrySet;
870:                return (es != null ? es : (entrySet = new EntrySet()));
871:            }
872:
873:            private final class EntrySet extends AbstractSet {
874:
875:                public Iterator iterator() {
876:                    return new HashIterator(ENTRIES, table.length - 1);
877:                }
878:
879:                public boolean contains(Object o) {
880:                    if (!(o instanceof  Map.Entry))
881:                        return false;
882:                    Map.Entry e = (Map.Entry) o;
883:                    Entry candidate = getEntry(e.getKey());
884:                    return candidate != null && candidate.equals(e);
885:                }
886:
887:                public boolean remove(Object o) {
888:                    return removeMapping(o) != null;
889:                }
890:
891:                public int size() {
892:                    return size;
893:                }
894:
895:                public void clear() {
896:                    ConcurrentHashMap.this .clear();
897:                }
898:            }
899:
900:            /**
901:             * Save the state of the <tt>ConcurrentHashMap</tt> instance to a stream
902:             * (i.e., serialize it).
903:             *
904:             * @serialData The <i>capacity</i> of the ConcurrentHashMap(the length of
905:             * the bucket array) is emitted(int), followed by the <i>size</i> of the
906:             * ConcurrentHashMap(the number of key-value mappings), followed by the key
907:             * (Object) and value(Object) for each key-value mapping represented by the
908:             * ConcurrentHashMap The key-value mappings are emitted in the order that
909:             * they are returned by <tt>entrySet().iterator()</tt>.
910:             */
911:            private void writeObject(ObjectOutputStream s) throws IOException {
912:                // Write out the threshold, loadfactor, and any hidden stuff
913:                s.defaultWriteObject();
914:
915:                // Write out number of buckets
916:                s.writeInt(table.length);
917:
918:                // Write out size(number of Mappings)
919:                s.writeInt(size);
920:                s.writeInt(maxSize);
921:
922:                // Write out keys and values(alternating)
923:                for (Iterator i = entrySet().iterator(); i.hasNext();) {
924:                    Map.Entry e = (Map.Entry) i.next();
925:                    s.writeObject(e.getKey());
926:                    s.writeObject(e.getValue());
927:                }
928:            }
929:
930:            private static final long serialVersionUID = -6452706556724125778L;
931:
932:            /**
933:             * Reconstitute the <tt>ConcurrentHashMap</tt> instance from a stream(i.e.,
934:             * deserialize it).
935:             */
936:            private void readObject(ObjectInputStream s) throws IOException,
937:                    ClassNotFoundException {
938:                // Read in the threshold, loadfactor, and any hidden stuff
939:                s.defaultReadObject();
940:
941:                // Read in number of buckets and allocate the bucket array;
942:                int numBuckets = s.readInt();
943:                table = new Entry[numBuckets];
944:
945:                // Read in size(number of Mappings)
946:                int size = s.readInt();
947:
948:                // read the max size
949:                maxSize = s.readInt();
950:
951:                // Read the keys and values, and put the mappings in the
952:                // ConcurrentHashMap
953:                for (int i = 0; i < size; i++) {
954:                    Object key = s.readObject();
955:                    Object value = s.readObject();
956:                    put(key, value);
957:                }
958:            }
959:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.