接口

List接口


List 接口是Java集合框架中的一部分,它继承自 Collection 接口。List 提供了对元素进行有序集合操作的方法。

特性

  • 有序List 接口中的元素是有序的,即元素按照它们被插入的顺序排列。
  • 可重复List 允许存储重复的元素。
  • 动态List 的大小可以根据需要动态变化。

常用方法

  • add(E e):向列表末尾添加一个元素。
  • add(int index, E element):在指定位置插入一个元素。
  • remove(int index):移除指定位置的元素,并返回被移除的元素。
  • remove(Object o):移除列表中第一次出现的指定元素。
  • get(int index):返回指定位置的元素。
  • set(int index, E element):用指定元素替换列表中指定位置的元素。
  • indexOf(Object o):返回第一次出现的指定元素的索引。
  • lastIndexOf(Object o):返回最后一次出现的指定元素的索引。
  • size():返回列表中的元素数量。
  • isEmpty():如果列表为空,返回 true

常用实现

ArrayList

  • 基于动态数组实现。
  • 支持快速随机访问。
  • 插入和删除操作可能较慢,特别是当需要在列表中间插入或删除元素时。

LinkedList

  • 基于双向链表实现。
  • 适合进行频繁的插入和删除操作。
  • 不支持快速随机访问。

Vector(过时)

  • 类似于 ArrayList,但它是同步的。
  • 通常不推荐使用,因为 ArrayList 提供了更好的性能。

Stack(过时)

  • 继承自 Vector,实现了栈的功能。
  • 遵循后进先出(LIFO)原则。

CopyOnWriteArrayList

  • 线程安全的变体,适用于迭代操作远多于修改操作的场景。

Set接口


Set 接口是Java集合框架中的一个接口,它继承自 Collection 接口。Set 集合中的元素不允许重复,并且没有特定的顺序。以下是 Set 接口的一些关键特性和常用实现:

特性

  • 不允许重复Set 接口保证不会包含重复的元素。
  • 无序:尽管 Set 接口本身不保证元素的顺序,但是某些实现(如 TreeSet)可能会根据元素的自然顺序或自定义顺序对元素进行排序。

常用方法

  • add(E e):向集合添加一个元素。如果集合中已经存在该元素,则返回 false
  • remove(Object o):从集合中移除指定元素。
  • contains(Object o):检查集合是否包含指定元素。
  • size():返回集合中的元素数量。
  • isEmpty():如果集合为空,返回 true

常用实现

HashSet

  • 基于哈希表实现。
  • 性能通常优于其他 Set 实现,特别是在添加、删除和查找元素时。

LinkedHashSet

  • 类似于 HashSet,但它维护了元素的插入顺序。

TreeSet

  • 基于红黑树实现。
  • 可以按照自然顺序或自定义顺序对元素进行排序。

CopyOnWriteArraySet

  • 线程安全的 Set 实现,适用于迭代操作远多于修改操作的场景。

示例用法

Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Cherry");

if (set.contains("Apple")) {
    System.out.println("Set contains Apple");
}

set.remove("Banana");

System.out.println("Set size: " + set.size());

Queue接口


Queue 接口是Java集合框架中的一部分,它扩展了 Collection 接口,用于表示处理元素的队列。队列通常遵循先进先出(FIFO)的原则,但某些实现可能提供其他类型的队列行为,例如优先队列。

特性

  • 先进先出:标准的队列实现遵循 FIFO 原则,即先添加到队列的元素将先被移除。
  • 容量限制:某些队列实现可能具有容量限制,当队列满了之后,再尝试添加元素可能会阻塞或抛出异常。
  • 阻塞行为:一些队列实现提供了阻塞操作,当队列为空时,从队列中获取元素的操作可能会阻塞,直到有元素可用。

常用方法

  • add(E e)offer(E e):向队列添加一个元素。offer 方法通常在无法添加元素时返回 false,而 add 方法可能会抛出一个 IllegalStateException
  • remove(E e)poll():从队列移除并返回头部元素。poll 方法在队列为空时返回 null,而 remove 方法可能会抛出一个 NoSuchElementException
  • element()peek():返回队列头部元素但不移除它。peek 方法在队列为空时返回 null,而 element 方法可能会抛出一个 NoSuchElementException
  • size():返回队列中的元素数量。

常用实现

  1. LinkedList

    • 除了作为 List 的实现,LinkedList 也可以作为 Queue 使用,因为它允许在两端进行快速的插入和删除操作。
  2. PriorityQueue

    • 一个基于优先级堆的队列实现,元素按照自然顺序或自定义的比较器进行排序。
  3. ArrayDeque

    • 一个双端队列实现,允许在队列的两端进行快速的插入和删除操作。
  4. 阻塞队列java.util.concurrent 包下)

    • 提供了一系列阻塞队列实现,例如:
      • LinkedBlockingQueue
      • ArrayBlockingQueue
      • SynchronousQueue
      • DelayQueue
    • 这些队列在进行插入或移除操作时可能会阻塞或等待。

示例用法

Queue<String> queue = new LinkedList<>();
queue.add("Apple");
queue.add("Banana");

String fruit = queue.poll(); // 取出并移除队列头部的元素 "Apple"
System.out.println("Removed: " + fruit);

String frontFruit = queue.peek(); // 查看队列头部的元素但不移除 "Banana"
System.out.println("Front fruit: " + frontFruit);

非阻塞队列

非阻塞队列是一种队列实现,它在进行入队(enqueue)和出队(dequeue)操作时不会使线程阻塞。这种队列通常用于并发编程中,特别是在多线程环境中,它允许多个线程以非阻塞的方式访问队列。

特性

  • 非阻塞:即使队列已满或为空,也不会使线程挂起或等待。
  • 高吞吐量:由于没有线程阻塞,非阻塞队列通常能够提供较高的吞吐量。
  • 低延迟:操作通常能够立即完成,减少了线程上下文切换的开销。

实现方式

非阻塞队列的实现通常依赖于以下技术:

  • 原子操作:使用原子变量和原子操作来保证队列操作的原子性。
  • 无锁编程:避免使用锁(synchronized blocks 或 locks),而是通过其他同步机制(如 CAS - Compare-And-Swap)来实现线程安全。
  • 数据结构:使用特定的数据结构,如环形缓冲区(ring buffer),来实现高效的入队和出队操作。

Java中的非阻塞队列

在Java中,java.util.concurrent 包提供了一些非阻塞队列的实现,例如:

  • ConcurrentLinkedQueue:基于链接节点的无界线程安全队列,用于在多个线程之间以 FIFO 顺序共享数据。
  • LinkedTransferQueue:类似于 ConcurrentLinkedQueue,但它提供了一些额外的特性,如支持在队列为空时,通过 transfer 方法阻塞等待元素的插入。
  • LinkedBlockingQueue:虽然 LinkedBlockingQueue 本身是一个阻塞队列,但它也可以配置为非阻塞模式,通过设置容量为 Integer.MAX_VALUE 来实现。

示例用法

以下是使用 ConcurrentLinkedQueue 的一个简单示例:

import java.util.concurrent.ConcurrentLinkedQueue;

public class NonBlockingQueueExample {
    private final ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<>();

    public void produce() {
        for (int i = 0; i < 10; i++) {
            queue.offer(i); // 非阻塞地添加元素
        }
    }

    public void consume() {
        Integer element;
        while ((element = queue.poll()) != null) {
            System.out.println("Consumed: " + element); // 非阻塞地移除并处理元素
        }
    }

    public static void main(String[] args) {
        NonBlockingQueueExample example = new NonBlockingQueueExample();
        // 可以启动多个线程来并发地调用 produce 和 consume 方法
    }
}

阻塞队列

阻塞队列(Blocking Queue)是一种特殊的队列,当队列进行入队(enqueue)或出队(dequeue)操作时,如果队列已满或为空,线程将会被阻塞,直到可以进行操作。这种队列在多线程环境中非常有用,因为它可以作为线程间通信的一种机制。

特性

  • 线程安全:阻塞队列是线程安全的,可以由多个线程并发访问。
  • 容量限制:阻塞队列可能有一个容量限制,超过这个限制后,入队操作将被阻塞,直到队列中有空间。
  • 阻塞操作:当队列为空时,从队列中取出元素的操作将阻塞,直到队列中有元素可取;当队列已满时,入队操作将阻塞,直到队列中有空间。

常用方法

  • put(E e):向队列添加一个元素。如果队列已满,调用线程将被阻塞,直到队列中有空间。
  • take():从队列中移除并返回头部元素。如果队列为空,调用线程将被阻塞,直到队列中有元素。
  • offer(E e, long timeout, TimeUnit unit):尝试在指定的时间内向队列添加一个元素。如果超时前队列未满,则返回 true;否则返回 false
  • poll(long timeout, TimeUnit unit):尝试在指定的时间内从队列中移除并返回头部元素。如果超时前队列非空,则返回元素;否则返回 null
  • remainingCapacity():返回队列的剩余容量。

常用实现

Java的 java.util.concurrent 包提供了多种阻塞队列的实现,包括:

  1. ArrayBlockingQueue:基于数组的有界阻塞队列。
  2. LinkedBlockingQueue:基于链表的可选容量阻塞队列。
  3. PriorityBlockingQueue:基于优先级堆的无界阻塞队列。
  4. SynchronousQueue:一个不存储元素的阻塞队列,每个插入操作必须等待一个相应的移除操作,反之亦然。
  5. DelayQueue:基于优先级堆的无界阻塞队列,只持有实现了 Delayed 接口的元素。
  6. LinkedTransferQueue:类似于 LinkedBlockingQueue,但提供了更高效的入队和出队操作。

示例用法

以下是使用 ArrayBlockingQueue 的一个示例:

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class BlockingQueueExample {
    private static final int QUEUE_SIZE = 10;
    private final BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(QUEUE_SIZE);

    public void produce() throws InterruptedException {
        for (int i = 0; i < QUEUE_SIZE * 2; i++) {
            queue.put(i); // 如果队列已满,这里会阻塞
            System.out.println("Produced: " + i);
        }
    }

    public void consume() throws InterruptedException {
        for (int i = 0; i < QUEUE_SIZE * 2; i++) {
            int number = queue.take(); // 如果队列为空,这里会阻塞
            System.out.println("Consumed: " + number);
        }
    }

    public static void main(String[] args) {
        BlockingQueueExample example = new BlockingQueueExample();
        Thread producer = new Thread(example::produce);
        Thread consumer = new Thread(example::consume);

        producer.start();
        consumer.start();
    }
}

Map接口


Map 接口是Java集合框架中用于存储键值对(key-value pairs)的一种数据结构。与 ListSet 集合不同,Map 允许我们通过键快速检索值。以下是 Map 接口的一些关键特性和常用实现:

特性

  • 键值对Map 存储了键(key)和值(value)的映射关系,每个键映射到一个特定的值。
  • 键唯一性Map 中的键是唯一的,不允许有重复的键。
  • 无序Map 接口本身不保证映射的顺序,但某些实现(如 LinkedHashMapTreeMap)可以按照某种顺序来遍历键值对。

常用方法

  • put(K key, V value):将指定的值与此映射中的指定键关联。
  • get(Object key):返回指定键所映射的值。
  • remove(Object key):如果存在一个键的映射关系,则将其从映射中移除。
  • keySet():返回映射中包含的键的 Set 视图。
  • values():返回映射中包含的值的 Collection 视图。
  • entrySet():返回映射中包含的键值映射关系的 Set 视图。
  • size():返回映射中键值对的数量。
  • isEmpty():如果映射不包含键值对,则返回 true。

常用实现

  1. HashMap

    • 基于哈希表的 Map 接口实现,它允许空键和空值。
    • 性能高效,但顺序不保证。
  2. TreeMap

    • 基于红黑树的 Map 接口实现,可以按照键的自然顺序或自定义顺序对键值对进行排序。
  3. LinkedHashMap

    • 类似于 HashMap,但它维护了插入顺序或者访问顺序,并且可以被配置为在达到最大容量时移除最老的条目。
  4. Hashtable

    • HashMap 类似,但它是同步的,不允许空键和空值。
  5. ConcurrentHashMap

    • 线程安全的 HashMap 实现,用于高并发环境。
  6. IdentityHashMap

    • 一种特殊的 Map 实现,它使用 == 而不是 equals() 方法来比较键。

示例用法

Map<String, Integer> map = new HashMap<>();
map.put("Apple", 1);
map.put("Banana", 2);

Integer value = map.get("Apple"); // 获取键 "Apple" 对应的值
System.out.println("Value: " + value);

map.remove("Banana"); // 移除键 "Banana" 的映射关系

System.out.println("Map size: " + map.size()); // 输出映射中键值对的数量
posted @ 2024-08-06 10:29  墨澜  阅读(6)  评论(0编辑  收藏  举报