List解决线程安全问题
1、使用Vector(),底层的实现原理是使用ArrayList()。加锁
2、使用Collections.synchronizedList(),底层是对于方法内部的代码块加锁。
3、CopyOnWriteArrayList:Write的时候总是要Copy(将原来array复制到新的array,修改后,将引用指向新数组)。任何可变的操作(add、set、remove等)都通过ReentrantLock 控制并发。
Set解决线程安全的问题
在Java中,有几种方法可以保证Set的线程安全性:
-
使用
Collections.synchronizedSet()
方法:可以通过Collections
类提供的SynchronizedSet
方法,将一个非线程安全的Set转换为线程安全的Set。例如:Set<String> set = new HashSet<>(); Set<String> synchronizedSet = Collections.synchronizedSet(set);
使用该方法返回的
SynchronizedSet
,对其进行操作时会自动进行同步,从而保证线程安全。 -
使用
ConcurrentSkipListSet
:ConcurrentSkipListSet
是Java提供的线程安全的有序集合实现。它基于跳表(SkipList)数据结构,支持高效的并发访问。例如:Set<String> set = new ConcurrentSkipListSet<>();
使用
ConcurrentSkipListSet
时,多个线程可以同时对其进行读写操作,而无需额外的同步措施。 -
使用
CopyOnWriteArraySet
:CopyOnWriteArraySet
是Java提供的线程安全的Set实现。它使用了"写时复制"的策略,即在进行修改操作时,会创建一个新的底层数组来存储数据,从而避免了对原有数据的修改操作导致的并发问题。例如:Set<String> set = new CopyOnWriteArraySet<>();
使用
CopyOnWriteArraySet
时,读操作不需要同步,而写操作会创建一个新的副本,因此对于读多写少的场景,可以提供较好的性能。
Map解决线程安全问题
1.使用HashTable,因为HashTable对于get,put方法加锁(使用synchronized修饰着两个方法)。
2.使用Collections.synchronizedMap。它是对所有的方法内部都添加了synchronized。相比于HashTable。他的粒度更细。是对于方法内部的代码块加锁。
3.使用ConcurrentHashMap<>(),他每次只给一个桶(数组项)加锁。
内部将整个哈希表分成多个段(Segments),每个段都维护着一个子哈希表。默认情况下,ConcurrentHashMap
的段数与 CPU 核心数相同,这样可以最大限度地提高并发性能。