在Java并发编程中,线程安全的数据结构是至关重要的。CopyOnWriteArrayList是Java并发包java.util.concurrent中的一种线程安全ArrayList实现。它的主要特点是写操作会创建底层数组的新副本来实现线程安全,而读操作总是在当前数组上操作,无需同步。
CopyOnWriteArrayList基于乐观锁的思路,采用写时复制(Copy-On-Write)策略,在修改数据时复制一份数组,然后对新数组进行修改,完成后再替换掉旧的数组。这种策略在读多写少的并发场景中表现优异,因为读操作无需同步,直接在原数组上操作,极大地提高了读取效率。
CopyOnWriteArrayList适用于读多写少的并发场景,如缓存、日志记录等。在这些场景中,读操作远多于写操作,CopyOnWriteArrayList的读性能优势可以得到充分发挥。然而,对于写操作频繁的场景,如订单处理、实时数据更新等,CopyOnWriteArrayList可能并不是最佳选择。
例如:以下场景,IP地址的黑白名单
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* ip地址黑白名单
*
* @author yang
* @version 1.0.0
* @date 2024/1/22 11:01
*/
public class IPAccessManager {
private final List<String> ipWhitelist;
private final List<String> ipBlacklist;
public IPAccessManager() {
// 使用CopyOnWriteArrayList来存储IP地址列表,保证线程安全
ipWhitelist = new CopyOnWriteArrayList<>(Arrays.asList("192.168.0.1", "10.0.0.1"));
ipBlacklist = new CopyOnWriteArrayList<>(Arrays.asList("192.168.0.2", "10.0.0.2"));
}
public boolean isAllowed(String ipAddress) {
// 检查IP地址是否在白名单中
if (ipWhitelist.contains(ipAddress)) {
return true; // 允许访问
}
// 检查IP地址是否在黑名单中
if (ipBlacklist.contains(ipAddress)) {
return false; // 拒绝访问
}
// 其他情况,可能需要进一步验证或询问用户
// doSomething
return true; // 默认允许访问(这只是一个示例,实际应用中可能需要更复杂的逻辑)
}
public static void main(String[] args) {
IPAccessManager accessManager = new IPAccessManager();
String ipAddress = "192.168.0.3"; // 示例IP地址
boolean isAllowed = accessManager.isAllowed(ipAddress);
if (isAllowed) {
System.out.println(ipAddress + "允许访问");
} else {
System.out.println(ipAddress + "拒绝访问");
}
}
}
CopyOnWriteArrayList是一种适用于读多写少并发场景的线程安全数据结构。它通过写时复制的策略实现了高效的读操作和线程安全。然而,由于每次写操作都需要复制整个数组,导致写性能和内存占用都有较大的开销。在使用CopyOnWriteArrayList时,需要根据实际需求进行权衡和选择。