1. 为自定义对象实现合适的 equals()
和 hashCode()
方法
equals()
方法:
- 首先,检查传入对象是否为
this
本身,如果是则返回 true
,这是一个快速短路的优化。
- 然后,检查传入对象是否为
null
或者是否与当前对象属于不同的类,如果是则返回 false
。
- 接着,将传入对象强制转换为当前类的类型(前提是前面的类检查通过)。
- 最后,比较对象中所有参与唯一性判断的关键属性。例如,如果自定义类
Person
有 name
和 age
两个属性决定唯一性,代码如下:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
hashCode()
方法:
- 一个好的
hashCode()
方法应该尽可能地为不同的对象返回不同的哈希值,以减少哈希冲突。
- 可以使用
Objects.hash()
方法,传入所有参与唯一性判断的属性。对于上述 Person
类:
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + (name != null? name.hashCode() : 0);
result = 31 * result + age;
return result;
}
2. 在高并发环境下对 Set
集合进行操作
- 使用
ConcurrentHashMap
构建线程安全的 Set
集合:
ConcurrentHashMap
本身不是 Set
,但可以用来构建线程安全的 Set
。可以利用 ConcurrentHashMap
的 Key
唯一性来实现类似 Set
的功能。
- 例如,创建一个基于
ConcurrentHashMap
的线程安全 Set
:
import java.util.concurrent.ConcurrentHashMap;
public class ThreadSafeSet<E> {
private final ConcurrentHashMap<E, Boolean> map = new ConcurrentHashMap<>();
public boolean add(E e) {
return map.putIfAbsent(e, true) == null;
}
public boolean remove(E e) {
return map.remove(e) != null;
}
public boolean contains(E e) {
return map.containsKey(e);
}
}
- 数据一致性:
ConcurrentHashMap
采用了分段锁等机制,在高并发情况下可以保证数据的一致性。对于 putIfAbsent
、remove
等操作,它们都是原子性的,所以在多线程环境下能正确地维护集合的状态。
- 性能:
ConcurrentHashMap
的分段锁机制允许多个线程同时访问不同的段,减少了锁竞争,从而提高了性能。相比传统的 Hashtable
(全表锁),在高并发场景下性能有显著提升。在构建线程安全 Set
时,利用 ConcurrentHashMap
的这些特性,可以保证在高并发下的高效操作。