容器 1.jpg

List

CopyOnWriteList

在写数据时需要加锁,防止写的时候出现并发问题,加锁成功后再进行复制
读的时候是不需要加锁的,并发的读取数据

Set

  • HashSet:哈希表是通过使用称为散列法的机制来存储信息的,元素并没有以某种特定顺序来存放;
  • LinkedHashSet:以元素插入的顺序来维护集合的链接表,允许以插入的顺序在集合中迭代;
  • TreeSet:是一个使用树结构存储SortedSet接口的实现,对象以升序顺序存储,访问和遍历的时间很快。
//依次插入d, a, u, e, s, q, p, r
HashSet --------[p, a, q, r, s, d, u, e]
LinkedHashSet --[d, a, u, e, s, q, p, r]
TreeSet --------[a, d, e, p, q, r, s, u]

HashSet输出是和原来的添加的顺序是不一致的,因为其保存的位置是根据其哈希值来确定.
TreeSet使用红黑树结构进行保存,因此其内部是有序的,输出也是有序的.
LinkedHashSet使用链表来保存,因此输出时和插入时的顺序是一致的.

Queue

LinkedList

Queue最简单的实现类,线程不安全

  • 增添元素
方法作用区别
add增加一个元素如果队列已满,则抛出一个IIIegaISlabEepeplian异常
offer添加一个元素并返回true 如果队列已满,则返回false。
  • 删除元素
方法作用区别
remove删除队列里面指定元素有则删除返回 true,没有则返回 false
poll移除并返回队列头部的元素如果队列为空,则返回null。该方法是不阻塞的
  • 返回头部元素
方法作用区别
element返回队列头部的元素如果队列为空,则抛出一个NoSuchElementException异常
peek返回队列头部的元素如果队列为空,则返回null。该方法是不阻塞的

BlockingQueue

BlockingQueue新增了一个阻塞的添加元素方法put和一个阻塞的移除元素方法take

方法作用区别
put添加一个元素并返回true如果队列已满则阻塞当前线程直到队列有空闲插入成功后返回 true,如果在阻塞的时候被其它线程设置了中断标志,则被阻塞线程会抛出 InterruptedException异常而返回,另外如果 e 元素为 null 则抛出 NullPointerException 异常
take移除并返回队列头部的元素如果队列为空则阻塞调用线程。如果队列为空则阻塞当前线程直到队列不为空然后返回元素,如果在阻塞的时候被其它线程设置了中断标志,则被阻塞线程会抛出 InterruptedException 异常而返回。

offer和poll也可以指定时间来阻塞

PriorityQueue

PriorityQueue是一个基于优先级的无界优先级队列。优先级队列的元素按照其自然顺序进行排序,或者根据构造队列时提供的 Comparator 进行排序,具体取决于所使用的构造方法。
该队列不允许使用 null 元素也不允许插入不可比较的对象(没有实现Comparable接口的对象)。
PriorityQueue 队列的头指排序规则最小那个元素。如果多个元素都是最小值则随机选一个。
PriorityQueue 是一个无界队列,但是初始的容量(实际是一个Object[]),随着不断向优先级队列添加元素,其容量会自动扩容,无需指定容量增加策略的细节。

DelayQueue

DelayQueue是一个无界阻塞队列,只有在延迟期满时,才能从中提取元素。

使用场景

缓存系统设计:使用DelayQueue保存缓存元素的有效期,用一个线程循环查询DelayQueue,一旦从DelayQueue中取出元素,就表示有元素到期。
定时任务调度:使用DelayQueue保存当天要执行的任务和执行的时间,一旦从DelayQueue中获取到任务,就开始执行,比如Timer,就是基于DelayQueue实现的。

使用条件:
存放DelayQueue的元素,必须继承Delay接口,Delay接口使对象成为延迟对象。
该接口强制实现两个方法:
1.CompareTo(Delayed o):用于比较延时,队列里元素的排序依据,这个是Comparable接口的方法,因为Delay实现了Comparable接口,所以需要实现。
2.getDelay(TimeUnit unit):这个接口返回到激活日期的--剩余时间,时间单位由单位参数指定。
此队列不允许使用null元素。

public class DelayQueue {
    static BlockingQueue<MyTask> tasks = new DelayQueue<>();

    static class MyTask implements Delayed {
        String name;
        long runningTime;

        MyTask(String name, long rt) {
            this.name = name;
            this.runningTime = rt;
        }

        @Override
        public int compareTo(Delayed o) {
            if (this.getDelay(TimeUnit.MILLISECONDS) < o.getDelay(TimeUnit.MILLISECONDS))
                return -1;
            else if (this.getDelay(TimeUnit.MILLISECONDS) > o.getDelay(TimeUnit.MILLISECONDS))
                return 1;
            else
                return 0;
        }

        @Override
        public long getDelay(TimeUnit unit) {
            return unit.convert(runningTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
        }

        @Override
        public String toString() {
            return name + " " + runningTime;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        long now = System.currentTimeMillis();
        MyTask t1 = new MyTask("t1", now + 5000);
        MyTask t2 = new MyTask("t2", now + 2000);
        MyTask t3 = new MyTask("t3", now + 3000);
        MyTask t4 = new MyTask("t4", now + 4000);
        MyTask t5 = new MyTask("t5", now + 1000);

        tasks.put(t1);
        tasks.put(t2);
        tasks.put(t3);
        tasks.put(t4);
        tasks.put(t5);

        System.out.println(tasks);

        for (int i = 0; i < 5; i++) {
            System.out.println(tasks.take());
        }
    }
}

SynchronousQueue

SynchronousQueue是一个内部只能包含一个元素的队列。插入元素到队列的线程被阻塞,直到另一个线程从队列中获取了队列中存储的元素。同样,如果线程尝试获取元素并且当前不存在任何元素,则该线程将被阻塞,直到线程将元素插入队列。

public class SynchronusQueue { //容量为0
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> strs = new SynchronousQueue<>();

        new Thread(() -> {
            try {
                System.out.println(strs.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        strs.put("aaa"); //阻塞等待消费者消费
//        strs.put("bbb");
        //strs.add("d");
        System.out.println(strs.size());
    }
}

LinkedTransferQueue

LinkedTransferQueue是LinkedBlockingQueue、SynchronousQueue(公平模式)、ConcurrentLinkedQueue三者的集合体,它综合了这三者的方法,并且提供了更加高效的实现方式。

队列LinkedTransferQueue和SynchronousQueue有些类似,但LinkedTransferQueue可以使用put、tryTransfer、transfer添加多个数据而不用等别的线程来获取。tryTransfer和transfer与put不同的是,tryTransfer和transfer可以检测是否有线程在等待获取数据,如果检测到就立即发送新增的数据给这个线程获取而不用放入队列。所以当使用tryTransfer和transfer往LinkedTransferQueue添加多个数据的时候,添加一个数据后,会先唤醒等待的获取数据的线程,再继续添加数据。

  • 当 put 时,如果有等待的线程,就直接将元素 “交给” 等待者, 否则直接进入队列。
  • put和 transfer 方法的区别是,put 是立即返回的, transfer 是阻塞等待消费者拿到数据才返回。transfer方法和 SynchronousQueue的 put 方法类似。
  • tryTransfer方法是用来试探生产者传入的元素是否能直接传给消费者。如果没有消费者等待接收元素,则返回false。和transfer方法的区别是tryTransfer方法无论消费者是否接收,方法立即返回,而transfer方法是必须等到消费者消费了才返回。
public class T09_TransferQueue {
    public static void main(String[] args) throws InterruptedException {
        LinkedTransferQueue<String> strs = new LinkedTransferQueue<>();

        new Thread(() -> {
            try {
                System.out.println(strs.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            try {
                System.out.println(strs.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        strs.transfer("aaa");
//        System.out.println(strs.tryTransfer("aaa"));

//        strs.put("aaa");
    }
}

Map

WeakHashMap

WeakHashMap 继承于AbstractMap,实现了Map接口。
和HashMap一样,WeakHashMap 也是一个散列表,它存储的内容也是键值对(key-value)映射,而且键和值都可以是null。
不过WeakHashMap的键是“弱键”。在 WeakHashMap 中,当某个键不再正常使用时,会被从WeakHashMap中被自动移除。更精确地说,对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。某个键被终止时,它对应的键值对也就从映射中有效地移除了。
这个“弱键”的原理呢?大致上就是,通过WeakReference和ReferenceQueue实现的。 WeakHashMap的key是“弱键”,即是WeakReference类型的;ReferenceQueue是一个队列,它会保存被GC回收的“弱键”。

IdentityHashMap

IdentityHashMap利用Hash表来实现Map接口,比较键(和值)时使用引用相等性代替对象相等性,也就是说使用 == 而不是使用 equals。

  • 比如对于要保存的key,k1和k2,当且仅当k1== k2的时候,IdentityHashMap才会相等,而对于HashMap来说,相等的条件则是:(k1==null ? k2==null : k1.equals(k2))。
  • IdentityHashMap不是Map的通用实现,它有意违反了Map的常规协定。并且IdentityHashMap允许key和value都为null。
  • 同HashMap,IdentityHashMap也是无序的,并且该类不是线程安全的,如果要使之线程安全,可以调用Collections.synchronizedMap(new IdentityHashMap(...))方法来实现。

hhhhh