• Queue(队列)
    主要是为了高并发准备的容器
    Deque:双端队列,可以反方向装或者取
  • 最开始jdk1.0只有Vector和hashtable 默认所有方法都实现了synchronized锁,线程安全但性能比较差,因此后续SUN意识到这个问题之后加了完全没加锁的hashmap,但是由于Hashmap完全没锁,SUN又想到能不能让Hashmap在有锁的时候用呢,此时添加了Collection,里面有一个Collection.synchronizedMap(new HashMap()),将Hashmap变成了加锁的版本,里面锁的粒度变小了,能部分提高性能,在JUC之后,新出来了ConcurrentHashtable由于Hashtable和Vectoy是古老的版本带过来的,所以现在基本不用,知道就行。
    1、HashTable性能测试
    1. public class Constants {
    2. public static final int COUNT = 1000000;
    3. public static final int THREAD_COUNT = 100;
    4. }
    1. public class T01_TestHashtable {
    2. static Hashtable<UUID, UUID> m = new Hashtable<>();
    3. static int count = Constants.COUNT;
    4. static UUID[] keys = new UUID[count];
    5. static UUID[] values = new UUID[count];
    6. static final int THREAD_COUNT = Constants.THREAD_COUNT;
    7. static {
    8. for (int i = 0; i < count; i++) {
    9. keys[i] = UUID.randomUUID();
    10. values[i] = UUID.randomUUID();
    11. }
    12. }
    13. static class MyThread extends Thread {
    14. int start;
    15. int gap = count/THREAD_COUNT;
    16. public MyThread(int start) {
    17. this.start = start;
    18. }
    19. @Override
    20. public void run() {
    21. for(int i=start; i<start+gap; i++) {
    22. m.put(keys[i], values[i]);
    23. }
    24. }
    25. }
    26. public static void main(String[] args) {
    27. long start = System.currentTimeMillis();
    28. Thread[] threads = new Thread[THREAD_COUNT];
    29. for(int i=0; i<threads.length; i++) {
    30. threads[i] =
    31. new MyThread(i * (count/THREAD_COUNT));
    32. }
    33. for(Thread t : threads) {
    34. t.start();
    35. }
    36. for(Thread t : threads) {
    37. try {
    38. t.join();
    39. } catch (InterruptedException e) {
    40. e.printStackTrace();
    41. }
    42. }
    43. long end = System.currentTimeMillis();
    44. System.out.println(end - start);
    45. System.out.println(m.size());
    46. //-----------------------------------
    47. start = System.currentTimeMillis();
    48. for (int i = 0; i < threads.length; i++) {
    49. threads[i] = new Thread(()->{
    50. for (int j = 0; j < 10000000; j++) {
    51. m.get(keys[10]);
    52. }
    53. });
    54. }
    55. for(Thread t : threads) {
    56. t.start();
    57. }
    58. for(Thread t : threads) {
    59. try {
    60. t.join();
    61. } catch (InterruptedException e) {
    62. e.printStackTrace();
    63. }
    64. }
    65. end = System.currentTimeMillis();
    66. System.out.println(end - start);
    67. }
    68. }

    相对来说,插入的时候ConcurrentHashMap相对于HashMap效率没有明显提高,但是读取的时候效率高很多。

  • ConcurrentSkipListMap 跳表结构,由于CAS在Tree这种结构上操作太复杂,然后冒出了跳表这种结构,底层时链表,为了查找效率,提取关键元素,制作新的链表,找的时候先找11->78,发现元素比78小,则与11比较,如果大,则在11-78中找,明显效率提高了。
    跳表:
  • 多线程尽量使用Queue,少用List、Set
  • CopyOnWrite,写时复制,读的时候不加锁,写的时候加锁,原理是:会在原来基础上Copy一个出来数组,在新的数组上写,写完后将引用指向新数组,过程中读的时候读的是原来数组,当写的过程结束之后读得是新数组,写时复制
  • CopyOnWriteArrayList,写(添加)的时候是加了锁的,里面先获取原数组的长度,创建新数组长度为原数组+1,读(get)的时候是加了锁的
    1. public boolean add(E e) {
    2. final ReentrantLock lock = this.lock;
    3. lock.lock();
    4. try {
    5. Object[] elements = getArray();
    6. int len = elements.length;
    7. Object[] newElements = Arrays.copyOf(elements, len + 1);
    8. newElements[len] = e;
    9. setArray(newElements);
    10. return true;
    11. } finally {
    12. lock.unlock();
    13. }
    14. }
    1. public E get(int index) {
    2. return get(getArray(), index);
    3. }
  • BlockingQueue  为线程池做准备,重点在blocking上,阻塞队列,有很多对多线程友好的方法。
    1、常用的一共三种,分别是无界的LinkedBlockingQueue(表示用Linked实现是,无界,除非内存溢出,添加方法put的区别是,put方法非要添加,如果满了就阻塞住,取方法    take(),非要取,如果没有了就阻塞,阻塞的原理就是实现了park(),线程阻塞住,进入wait状态)、
    2、有界的ArrayBlockingQueue(表示用Array实现是,有界,除非内存溢出,满了之后程序会阻塞住,等消费者)、
    3、DelayQueue(实现时间上的排序)、
    4、synchronusQueue(实现线程中间传输内容、任务)、
    5、TransferQueue(是前面几种的组合,也可以传输任务,并且不是传递一个,可以传递多个)
  • ConcurrentLinkedQueue
    里面一些友好的方法添加 offer()(返回值是Boolean类型,true表示成功,)、peak()(取)
  • Queue 与 List的区别,主要在于Queue添加了很多对线程友好的API,比如offer peek poll
    这其中一个子类BlockingQueue在上面(offer peek poll)的基础上添加了put take ->主要是实现了阻塞,可以自然而然的实现任务队列,也就是生产者、消费者模型,这是多线程中最重要的模型,是MQ的基础(必问内容)
  • DelayQueue,可以实现等待时间,类实现Delayed接口,同时设置运行时间runningtime,时间等待越短的优先运行,实现Compare接口,重写方法来确定任务执行队列
    按时间进行任务调度。本质是priorityQueue。
    1. static BlockingQueue<MyTask> tasks = new DelayQueue<>();
    2.  
    3. static Random r = new Random();
    4.  
    5. static class MyTask implements Delayed {
    6. String name;
    7. long runningTime;
    8.  
    9. MyTask(String name, long rt) {
    10. this.name = name;
    11. this.runningTime = rt;
    12. }
    13.  
    14. @Override
    15. public int compareTo(Delayed o) {
    16. if(this.getDelay(TimeUnit.MILLISECONDS) < o.getDelay(TimeUnit.MILLISECONDS))
    17. return -1;
    18. else if(this.getDelay(TimeUnit.MILLISECONDS) > o.getDelay(TimeUnit.MILLISECONDS))
    19. return 1;
    20. else
    21. return 0;
    22. }
    23.  
    24. @Override
    25. public long getDelay(TimeUnit unit) {
    26.  
    27. return unit.convert(runningTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
    28. }
    29.  
    30. @Override
    31. public String toString() {
    32. return name + " " + runningTime;
    33. }
    34. }

    main方法:

    1. public static void main(String[] args) throws InterruptedException {
    2. long now = System.currentTimeMillis();
    3. MyTask t1 = new MyTask("t1", now + 1000);
    4. MyTask t2 = new MyTask("t2", now + 2000);
    5. MyTask t3 = new MyTask("t3", now + 1500);
    6. MyTask t4 = new MyTask("t4", now + 2500);
    7. MyTask t5 = new MyTask("t5", now + 500);
    8.  
    9. tasks.put(t1);
    10. tasks.put(t2);
    11. tasks.put(t3);
    12. tasks.put(t4);
    13. tasks.put(t5);
    14.  
    15. System.out.println(tasks);
    16.  
    17. for(int i=0; i<5; i++) {
    18. System.out.println(tasks.take());
    19. }
    20. }

    结果:

    1. t5 1587472415617
    2. t1 1587472416117
    3. t3 1587472416617
    4. t2 1587472417117
    5. t4 1587472417617
  • PriorityQueue,会默认对任务排序,最小最优先,里面是小顶堆
    Demo:
    1. public class T07_01_PriorityQueque {
    2. public static void main(String[] args) {
    3. PriorityQueue<String> q = new PriorityQueue<>();
    4. q.add("c");
    5. q.add("e");
    6. q.add("a");
    7. q.add("d");
    8. q.add("z");
    9. for (int i = 0; i < 5; i++) {
    10. System.out.println(q.poll());
    11. }
    12. }
    13. }
    14. //打印结果:a、c、d、e、z
  • synchronusQueue,容量为0,不是用来装东西,主要是用来一个线程给另一个线程下达任务,与之前的exchanger容器类似,不可以用add方法,里面容器为0,不可以装东西。应用场景是:做某件事需要等待结果完成才继续执行接下来的任务。

JAVA高并发集合详解的更多相关文章

  1. 《JAVA高并发编程详解》-七种单例模式

  2. 《JAVA高并发编程详解》-volatile和synchronized

  3. 《JAVA高并发编程详解》-并发编程有三个至关重要的特性:原子性,有序性,可见性

  4. 《JAVA高并发编程详解》-类的加载过程简介

  5. 《JAVA高并发编程详解》-wait和sleep

  6. 《JAVA高并发编程详解》-程序可能出现死锁的场景

  7. 《JAVA高并发编程详解》-Thread start方法的源码

    Thread start方法的源码:

  8. 《JAVA高并发编程详解》-Thread对象的启动

    当我们用关键字new创建一个Thread对象时,此时它并不处于执行状态,因为没有调用start方法启动该线程,那么线程的状态为NEW状态,NEW状态通过start方法进入RUNNABLE状态. 线程一 ...

  9. Java中的集合详解及代码测试

    1:对象数组 (1)数组既可以存储基本数据类型,也可以存储引用类型.它存储引用类型的时候的数组就叫对象数组. 2:集合(Collection) (1)集合的由来 我们学习的是Java -- 面向对象 ...

随机推荐

  1. 学习JUC源码(3)——Condition等待队列(源码分析结合图文理解)

    前言 在Java多线程中的wait/notify通信模式结尾就已经介绍过,Java线程之间有两种种等待/通知模式,在那篇博文中是利用Object监视器的方法(wait(),notify().notif ...

  2. FeignClient spi 调用 短路异常 & 线程池配置

    FeignClient spi 调用 短路异常 & 线程池配置 默认配置见:HystrixThreadPoolProperties 线程池对象:com.netflix.hystrix.Hyst ...

  3. JAVA顺序结构和选择结构

    顺序结构 JAVA的基本结构就是顺序结构,除非特别指明,否则按顺序一句一句执行 顺序结构是最简单的算法结构 语句和语句直接,框与框直接就是按从上到下的顺序执行的,它是由若干个依次执行的处理步骤组成的, ...

  4. 知乎上看到的一篇讲解Epoll的文章,较形象生动

    作者:蓝形参链接:https://www.zhihu.com/question/20122137/answer/14049112来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...

  5. druid监控

    1 @ConfigurationProperties(prefix = "spring.datasource") 2 @Bean 3 public DataSource druid ...

  6. logback运行时动态创建日志文件

    package com.example.demo.config; import ch.qos.logback.classic.Level; import ch.qos.logback.classic. ...

  7. MySQL 中的WAL机制

    本文主要概括的是 WAL 机制涉及的三种日志,具体与其他组件的联系.执行可查看 一条 sql 的执行过程详解 .MySQL中的事务原理和锁机制 . 是什么 WAL,全称是Write-Ahead Log ...

  8. 递归的三部解题曲 关联leetcode 104. 二叉树最大深度练习

    递归关心的三点 1. 递归的终止条件 2. 一级递归需要做什么 3. 返回给上一级递归的返回值是什么 递归三部曲 1. 找到递归的终止条件:递归什么时候结束 2. 本级递归做什么:在这级递归中应当完成 ...

  9. 杭电1720---A+B Coming(技巧:使用%x)

    Problem Description Many classmates said to me that A+B is must needs. If you can't AC this problem, ...

  10. 获取微信Token值

    /** * 获取Token值 * @param $corpid * @param $corpsecret * @return mixed * @author 宁佳兵 <meilijing.nin ...