1. How does ArrayList keep threads safe?
/ / the answer:
// Method 1:
SynchronizedList adds the synchronized lock to the set add remove method of the collection
List<Object> list = Collections.synchronizedList(new ArrayList<>());
// Method 2:
// Use thread-safe CopyOnWriteArrayList, which also locks increment, subtraction, and modification methods: final ReentrantLock lock = this.lock;
// Method 3:
// Create a wrapper class that inherits ArrayList and controls the add Set remove method according to the business
Copy the code
2. Initial capacity and expansion of Vector and ArrayList?
- They both have an initial capacity of 0, that is, 0 when the null parameter constructor is invoked, with the initial capacity value 10 attached to the first addition of element data
- When the Vector is expanded, if capacityIncrement is not specified or the value is not greater than 0, the capacityIncrement is doubled each time. Otherwise, the capacityIncrement is capacityIncrement
- ArrayList expands by 1.5 times each time
3. Do I need to expand CopyOnWriteArrayList to add new elements? How is it done?
- CopyOnWriteArrayList is not a dynamically expanded array and cannot be dynamically expanded. Its thread safety is guaranteed by adding a ReentrantLock
- When adding elements to CopyOnWriteArrayList, the thread acquirement the lock, the add method creates a new array of capacity (old array capacity +1), copies the old array data to that array, and places the new data at the end of the new array
The code is as follows:
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally{ lock.unlock(); }}Copy the code
CopyOnWriteArrayList works for reading too much and writing too little! Because each call to a method that changes the array structure requires a new array, performance is low!
4. What is the difference between HashMap and HashTable?
HashMap
- HashMap: The underlying HashMap is based on an array + a linked list + a red-black tree. It is not thread-safe and has a default capacity of 16, allowing empty keys and values
- The initial
size
Is 16. Capacity expansion:newsize = oldsize << 1
.Size must be 2 to the NTH power - When the total number of elements in the Map exceeds that of the Entry array75%In order to reduce the length of the linked list, element allocation is calculated more evenly
index
Methods:Index = hash & (tab.length - 1)
- Each time the Map is expanded, the elements in the original array are recalculated and inserted again
HashTable
- HashTable: the underlyingArray + linked listImplementation, neither key nor value can be
null
.Thread safetyTo achieve thread-safety, lock (synchroized
ConcurrentHashMap optimizes the entire HashTable - The initial
size
Is 11. Capacity expansion:(tab.length << 1) + 1
- To calculate
index
Method:index = (hash & 0x7FFFFFFF) % tab.length
The difference between
- HashMap is not thread-safe, HashTable is thread-safe
- A HashMap allows NULL as an entry key or value, whereas a Hashtable does not
- HashMap contains containsValue and containsKey. Because the CONTAINS method is misleading
- Hashtable inherits from the Dictionary class, and HashMap is an implementation class of the Map interface
Select index bucket from HashMap and HashTable
- A HashMap:
Index = hash & (tab.length - 1)
- HashTable:
index = (hash & 0x7FFFFFFF) % tab.length
Both formulas for bucket index are designed to make the bucket index obtained by each calculation more scattered, which can reduce hash conflicts.
HashTable:
0x7FFFFFFF
是0111 1111 1111 1111 1111 1111 1111 1111 1111 1111
: all 1’s except the sign bit(hash & 0x7FFFFFFF)
The result will be a positive integer(hash & 0x7FFFFFFF) % tab.length
The index result is always a positive integer and ensures that the value of index is intab.length
Within the scope of!- If the array length of a HashTable is odd, fewer hash collisions will occur. If the array length of a HashTable is even, more hash collisions will occur. Therefore, the initial capacity is 11 and the expansion is
newsize = olesize << 1+1
, ensure that each expansion result is an odd number
HashMap:
- The initial capacity is 16. When the number of valid data reaches 0.75 times of the array capacity, capacity expansion is triggered
- Bucket level calculation formula:
Index = hash & (tab.length - 1)
When calculating bucket index, the capacity must be 2 to the NTH power, that is, an even number. In this way, to reduce hash conflicts, expand:newsize = oldsize << 1
And you get even numbers - In addition, when the list length in the bucket is larger than 8 and the array length reaches 64, the list is tree-like, and when the list length is smaller than 6, the list is anti-tree-like
- The header interpolation method used in the pre-hashMap of JDK1.8 has the advantage of being more efficient than the tail interpolation method because it does not need to traverse the list once before inserting data
- In JDK1.8, we use tail interpolation to determine whether the length of the list is greater than 8
- HashMap resolves hash conflicts using the linked list method
- HashMap inserts data first and then determines whether the repository is needed!
5. What is the difference between HashMap and TreeMap?
- HashMap was introduced above, so let’s go straight to TreeMap
- TreeMap is based on the balanced binary tree (red-black tree), which can customize the sorting rules. To implement the Comparator interface, it can easily implement various sorts of internal elements, but the performance is worse than that of HashMap
6. Relationship between Set and Map
- The core of both is to store a set of unique objects without repeating elements
- Each implementation of a Set is an encapsulation of the corresponding Map
- For example, the HashSet underlying layer encapsulates the HashMap, and the TreeSet underlying layer encapsulates the TreeMap
7. What is the sort of plugin Map?
- LinkedHashMap, sorted by element addition order (can also be set to sorted by access order)
- TreeMap, you can sort by nature or by custom
TreeMap(Comparetor c)
8. Why did the underlying HashMap choose a red-black tree over another tree, such as a binary lookup tree? Why did it not start with a red-black tree, but only tree when the list length reached 8 and the array capacity was greater than 64?
- Binary search tree will also become a linear structure in special cases, which has the same depth traversal problem as the original long list and slow search performance, such as:
- The main purpose of using red-black tree is to improve the speed of data search. Red-black tree is a balanced binary tree. After inserting new data, it will maintain balance through left-rotation, right-rotation, color change and other operations to solve the problem of the depth of single-linked list query
- The reason why a red-black tree is not used at the beginning is that traversing a linear linked list consumes less resources than traversing a red-black tree when the number of data in the list is small (because of a small amount of data, the red-black tree itself selects and changes color to maintain balance also need to consume resources), so the linear table is used in the early stage
- The reason for using 8 as the tree threshold is that after extensive testing, 8 is the most appropriate value