Dictionary
类,是 Java 早期提供的线程安全哈希表。其线程安全的实现方式是对每个方法都使用 synchronized
关键字进行同步。例如,在调用 put
、get
等方法时,整个 HashTable 会被锁定,其他线程必须等待当前线程释放锁后才能访问该方法。java
import java.util.Hashtable;
public class HashTableExample {
public static void main(String[] args) {
Hashtable hashtable = new Hashtable<>();
// 线程安全的 put 操作
hashtable.put("one", 1);
}
}
Segment
(段),每个 Segment
相当于一个小的 HashTable,每个 Segment
都有自己的锁。不同的 Segment
可以被不同的线程同时访问,只要访问的不是同一个 Segment
,就不会产生锁竞争,从而提高了并发性能。synchronized
来保证并发操作的安全性。它使用数组 + 链表 + 红黑树的数据结构,在进行插入、删除和查找操作时,首先通过哈希值找到对应的桶,然后对桶首节点加锁,锁的粒度更小,性能更高。java
import java.util.concurrent.ConcurrentHashMap;
public class ConcurrentHashMapExample {
public static void main(String[] args) {
ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap<>();
// 并发安全的 put 操作
concurrentHashMap.put("one", 1);
}
}
null
,而 ConcurrentHashMap 同样不允许键为 null
,如果插入 null
键会抛出 NullPointerException
。LinkedHashMap
继承自 HashMap
,它在 HashMap
的基础上维护了一个双向链表。这个双向链表定义了元素的迭代顺序,默认情况下是插入顺序,即元素按照插入的先后顺序进行迭代;也可以通过构造函数将其设置为访问顺序,即最近访问的元素会被移动到链表尾部。
java
import java.util.LinkedHashMap;
import java.util.Map;
public class LinkedHashMapExample {
public static void main(String[] args) {
// 创建一个按照插入顺序排序的 LinkedHashMap
LinkedHashMap linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("one", 1);
linkedHashMap.put("two", 2);
linkedHashMap.put("three", 3);
for (Map.Entry entry : linkedHashMap.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
}
HashMap
,具备 HashMap
的基本特性,如快速的查找、插入和删除操作。LinkedHashMap
来存储缓存数据,当缓存满时,自动移除最久未使用的元素。java
import java.util.LinkedHashMap;
import java.util.Map;
public class LRUCache extends LinkedHashMap {
private final int capacity;
public LRUCache(int capacity) {
// 第三个参数设置为 true 表示按照访问顺序排序
super(capacity, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > capacity;
}
};
this.capacity = capacity;
}
public static void main(String[] args) {
LRUCache cache = new LRUCache<>(2);
cache.put(1, 1);
cache.put(2, 2);
System.out.println(cache.get(1)); // 返回 1
cache.put(3, 3); // 该操作会使得关键字 2 作废
System.out.println(cache.get(2)); // 返回 -1 (未找到)
cache.put(4, 4); // 该操作会使得关键字 1 作废
System.out.println(cache.get(1)); // 返回 -1 (未找到)
System.out.println(cache.get(3)); // 返回 3
System.out.println(cache.get(4)); // 返回 4
}
}
java
import java.util.HashMap;
import java.util.Map;
public class HashMapExample {
public static void main(String[] args) {
HashMap hashMap = new HashMap<>();
hashMap.put("one", 1);
hashMap.put("two", 2);
hashMap.put("three", 3);
for (Map.Entry entry : hashMap.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
}
HashSet
基于 HashMap
实现,它不允许存储重复的元素。HashSet
内部使用一个 HashMap
来存储元素,将元素作为键,值统一为一个静态常量对象 PRESENT
。当向 HashSet
中添加元素时,实际上是将该元素作为键插入到内部的 HashMap
中,值为 PRESENT
。
java
import java.util.HashSet;
public class HashSetExample {
public static void main(String[] args) {
HashSet hashSet = new HashSet<>();
hashSet.add("one");
hashSet.add("two");
hashSet.add("three");
for (String element : hashSet) {
System.out.println(element);
}
}
}
HashMap
的键的唯一性来保证。HashMap
实现,利用 HashMap
的哈希算法和存储结构来实现快速的查找和插入操作。HashSet
在去重场景中的应用,例如对一个包含重复元素的列表进行去重操作。java
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
public class DuplicateRemoval {
public static void main(String[] args) {
List listWithDuplicates = new ArrayList<>();
listWithDuplicates.add("one");
listWithDuplicates.add("two");
listWithDuplicates.add("one");
HashSet set = new HashSet<>(listWithDuplicates);
List listWithoutDuplicates = new ArrayList<>(set);
for (String element : listWithoutDuplicates) {
System.out.println(element);
}
}
}
null
。它使用哈希表来存储元素,当发生哈希冲突时,会通过链表或红黑树来解决。java
import java.util.HashMap;
import java.util.Map;
public class HashMapExample {
public static void main(String[] args) {
HashMap hashMap = new HashMap<>();
hashMap.put("one", 1);
hashMap.put("two", 2);
System.out.println(hashMap.get("one"));
}
}
HashMap
实现,元素作为键存储,值为一个固定的常量对象。它不允许存储重复元素,通过 HashMap
的键的唯一性来保证。java
import java.util.HashSet;
public class HashSetExample {
public static void main(String[] args) {
HashSet hashSet = new HashSet<>();
hashSet.add("one");
hashSet.add("two");
System.out.println(hashSet.contains("one"));
}
}
null
,而 HashSet 允许存储一个 null
元素。HashMap
和 HashSet
在处理哈希冲突时的性能差异。Collections.sort
是 Java 集合框架中用于对列表进行排序的静态方法。它有两种重载形式:
RandomAccess
接口的列表(如 ArrayList
),使用双轴快速排序(Dual - pivot Quicksort)。双轴快速排序是一种改进的快速排序算法,它选择两个轴元素,将数组分为三个部分,从而减少了比较和交换的次数,平均时间复杂度为 O(nlogn)。RandomAccess
接口的列表(如 LinkedList
),先将列表元素复制到一个数组中,对数组进行排序,再将排序后的元素复制回列表。java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CollectionsSortExample {
public static void main(String[] args) {
List list = new ArrayList<>();
list.add(3);
list.add(1);
list.add(2);
Collections.sort(list);
for (Integer num : list) {
System.out.println(num);
}
}
}
Collections.sort
是不稳定的排序算法,即相等元素的相对顺序可能会改变。哈希算法是一种将任意长度的输入数据转换为固定长度的输出数据的算法,输出数据通常称为哈希值或散列值。哈希算法具有以下特点:
hasNext()
、next()
和 remove()
方法。hasNext()
用于判断集合中是否还有下一个元素,next()
用于返回下一个元素,remove()
用于删除最后一次调用 next()
方法返回的元素。Iterator
可以在遍历过程中安全地删除元素。java
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorExample {
public static void main(String[] args) {
List list = new ArrayList<>();
list.add("one");
list.add("two");
list.add("three");
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
if (element.equals("two")) {
iterator.remove();
}
}
for (String element : list) {
System.out.println(element);
}
}
}
hasMoreElements()
和 nextElement()
方法。hasMoreElements()
用于判断集合中是否还有更多元素,nextElement()
用于返回下一个元素。Enumeration
不支持在遍历过程中删除元素。java
import java.util.Enumeration;
import java.util.Vector;
public class EnumerationExample {
public static void main(String[] args) {
Vector vector = new Vector<>();
vector.add("one");
vector.add("two");
vector.add("three");
Enumeration enumeration = vector.elements();
while (enumeration.hasMoreElements()) {
String element = enumeration.nextElement();
System.out.println(element);
}
}
}
Enumeration
是线程安全的,因为它没有 remove()
方法,不会改变集合的结构;而 Iterator
在多线程环境下使用时需要注意线程安全问题。Iterator
的子类(如 ListIterator
)的特点,ListIterator
是 Iterator
的子接口,它可以双向遍历列表,并且支持在遍历过程中添加、修改和删除元素。java
import java.util.ArrayList;
import java.util.List;
public class ArrayListExample {
public static void main(String[] args) {
List arrayList = new ArrayList<>();
arrayList.add("one");
arrayList.add("two");
System.out.println(arrayList.get(0));
}
}
java
import java.util.LinkedList;
import java.util.List;
public class LinkedListExample {
public static void main(String[] args) {
List linkedList = new LinkedList<>();
linkedList.add("one");
linkedList.add("two");
System.out.println(linkedList.get(0));
}
}
ArrayList
类似,但它是线程安全的,所有方法都使用 synchronized
关键字进行同步。默认初始容量为 10,每次扩容为原来的 2 倍。java
import java.util.Vector;
import java.util.List;
public class VectorExample {
public static void main(String[] args) {
List vector = new Vector<>();
vector.add("one");
vector.add("two");
System.out.println(vector.get(0));
}
}
Collections.synchronizedList
方法将 ArrayList 转换为线程安全的列表。应用
volatile
修饰的变量的值,其他线程能够立即看到最新的值。这是因为 volatile
变量会直接从主内存中读取和写入,而不是从线程的本地缓存中读取和写入。但它不保证原子性,例如对 volatile
变量进行自增操作不是原子操作。java
public class VolatileExample {
private static volatile int counter = 0;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter++;
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter++;
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(counter);
}
}
synchronized
修饰的方法或代码块,从而保证了线程安全,既保证了可见性,也保证了原子性。当一个线程进入 synchronized
方法或代码块时,会获得对象的锁,其他线程必须等待该线程释放锁后才能进入。java
public class SynchronizedExample {
private static int counter = 0;
public static synchronized void increment() {
counter++;
}
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
increment();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(counter);
}
}
volatile
和 synchronized
在 JMM 中的实现机制。volatile
和 synchronized
在不同并发场景下的优化使用,例如使用 volatile
结合 CAS 操作实现无锁算法。友情提示:本文已经整理成文档,可以到如下链接免积分下载阅读
https://download.csdn.net/download/ylfhpy/90498379