上一篇地址:赶紧收藏!2024 年最常见 100道 Java 基础面试题(十四)-CSDN博客
二十九、在Queue
中poll()
和remove()
有什么区别?
Queue
是Java中一个接口,代表了一个队列,它是一种特殊的集合,遵循先进先出(FIFO)的原则。poll()
和remove()
是Queue
接口的两个方法,它们用于从队列中移除元素,但它们的行为略有不同:
-
poll()
方法:poll()
方法从队列头部移除并返回元素。如果队列是空的,poll()
方法将返回null
。它不会抛出异常。
-
remove()
方法:remove()
方法也用于从队列头部移除元素,但是,如果队列为空,remove()
方法将抛出一个NoSuchElementException
。在行为上,它更像是集合的remove()
方法。
-
空队列时的行为:
- 当队列为空时,
poll()
和remove()
的主要区别在于对空队列的处理方式。poll()
在队列为空时返回null
,而remove()
会抛出异常。
- 当队列为空时,
-
使用场景:
- 如果你不确定队列是否为空,并且希望在队列为空时安全地处理,那么
poll()
是一个更好的选择,因为它不会抛出异常。 - 如果你确信队列不为空,或者在队列为空时宁愿让程序抛出异常,那么可以使用
remove()
方法。
- 如果你不确定队列是否为空,并且希望在队列为空时安全地处理,那么
-
与
ArrayList
和LinkedList
的关系:- 在Java中,
ArrayList
和LinkedList
都实现了Queue
接口。LinkedList
作为队列使用时,其poll()
和remove()
方法的行为与上面描述的一致。而ArrayList
作为队列使用时,通常推荐只使用remove()
方法来保持与Queue
接口的一致性,因为ArrayList
的随机访问特性使得poll()
方法的实现可能不够高效。
- 在Java中,
示例代码:
import java.util.LinkedList;
import java.util.Queue;
public class QueueExample {
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<>();
queue.add(1);
queue.add(2);
// 使用poll()方法
Integer polledValue = queue.poll(); // 返回1,队列中的第一个元素
System.out.println("Polled value: " + polledValue);
// 使用remove()方法
// Integer removedValue = queue.remove(); // 返回2,队列中的第一个元素
// System.out.println("Removed value: " + removedValue);
// 如果队列为空,remove()将抛出NoSuchElementException
// 如果队列为空,poll()将返回null
Integer emptyPoll = queue.poll(); // 返回null,队列为空
System.out.println("Empty poll: " + emptyPoll);
}
}
总结:
Queue
的poll()
方法在队列为空时返回null
,而remove()
方法在队列为空时抛出异常。- 在处理队列时,选择使用
poll()
或remove()
应基于对空队列的预期处理方式。
三十、哪些集合类是线程安全的?
在Java中,线程安全的集合类可以安全地在多线程环境中使用,而不需要额外的同步措施。以下是一些线程安全的集合类:
-
Collections.synchronizedList(List<T> list)
:- 返回一个线程安全的
List
包装器,所有List的列表操作都被同步。
- 返回一个线程安全的
-
Collections.synchronizedSet(Set<T> s)
:- 返回一个线程安全的
Set
包装器,所有Set的集合操作都被同步。
- 返回一个线程安全的
-
Collections.synchronizedMap(Map<K,V> m)
:- 返回一个线程安全的
Map
包装器,所有Map的映射操作都被同步。
- 返回一个线程安全的
-
Vector<T>
:Vector
是ArrayList
的线程安全版本,所有方法都是同步的。
-
Stack<T>
:Stack
是Vector
的子类,也是线程安全的,用于实现栈的功能。
-
Hashtable<K,V>
:Hashtable
是线程安全的Map
实现,所有方法都是同步的。
-
ConcurrentHashMap<K,V>
:- 从Java 1.5开始,
ConcurrentHashMap
提供了更好的并发性能,它使用分段锁来允许并发的读写操作。
- 从Java 1.5开始,
-
CopyOnWriteArrayList<T>
:- 这是一个线程安全的变体,适用于读操作远多于写操作的场景。
-
CopyOnWriteArraySet<T>
:- 这是一个线程安全的
Set
,使用CopyOnWriteArrayList
作为其底层数据结构。
- 这是一个线程安全的
-
ArrayBlockingQueue<T>
:- 这是一个由
Array
支持的有界阻塞队列,适用于需要阻塞操作的场景。
- 这是一个由
-
LinkedBlockingQueue<T>
:- 这是一个可选容量的阻塞队列,基于链表实现。
-
PriorityBlockingQueue<T>
:- 这是一个无界优先级队列,元素按照自然顺序排序或根据提供的
Comparator
排序。
- 这是一个无界优先级队列,元素按照自然顺序排序或根据提供的
示例代码:
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
public class ThreadSafeCollections {
public static void main(String[] args) {
// 使用Collections工具类创建线程安全的List
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
// Vector是线程安全的
Vector<String> vector = new Vector<>();
// Hashtable是线程安全的Map
Hashtable<String, String> hashtable = new Hashtable<>();
// ConcurrentHashMap是线程安全的Map,提供更好的并发性能
ConcurrentHashMap<String, String> concurrentHashMap = new ConcurrentHashMap<>();
}
}
总结:
- 线程安全的集合类可以避免在多线程环境中由于并发修改导致的问题。
- Java提供了多种线程安全的集合类,包括同步包装器和专门的线程安全集合类。
- 在选择线程安全的集合类时,应考虑并发性能和特定场景的需求。例如,
ConcurrentHashMap
通常比Hashtable
提供更好的性能,因为它允许更多的并发操作。