O(n²)的三个排序算法
今天复习下最简单的三个排序算法,一个是选择排序,一个是插入排序,一个是冒泡排序,三者时间复杂度都是O(n²),通过分析来发现三者的优劣,以及对最好的情况和最坏的情况进行分析。 另外,这三中排序算法都是基于比较的排序算法。基于比较的排序算法的执行过程,会涉及两种操作,一种是元素比较大小,另一种是元素交换或移动。所以,如果我们在分析排序算法的执行效率的时候,应该把比较次数和交换(或移动)次数也考虑进去。
今天复习下最简单的三个排序算法,一个是选择排序,一个是插入排序,一个是冒泡排序,三者时间复杂度都是O(n²),通过分析来发现三者的优劣,以及对最好的情况和最坏的情况进行分析。 另外,这三中排序算法都是基于比较的排序算法。基于比较的排序算法的执行过程,会涉及两种操作,一种是元素比较大小,另一种是元素交换或移动。所以,如果我们在分析排序算法的执行效率的时候,应该把比较次数和交换(或移动)次数也考虑进去。
我们知道SpringBoot的理念就是约定大于配置,这也使得我们在开发应用程序的过程更加便捷,以前的大量XML配置直接是噩梦呀,现在出现了SpringBoot明显降低了开发成本,而且大量的注解的使用帮我们省略掉了很多代码。本篇文章主要探究的是SpringBoot是如何实现自动配置并且如何加载配置Bean的,其实主要就是探究@EnableAutoConfiguration注解究竟发挥了怎样的作用。
ICO容器的结构如上图所示,首先要让IOC容器去读取Bean的配置信息,并在容器中生成一份相应的Bean定义注册表,根据这张注册表去实例化Bean,装配好Bean之间的依赖关系,为上层提供准备就绪的环境,Spring提供一个配置文件描述Bean还有Bean之间的依赖关系,利用Java语言的反射功能实例化Bean并建立Bean之间的依赖关系。
SpringIOC是Spring Core最核心的部分,要了解控制反转(Inversion of Control),我觉得有必要先了解软件设计的一个重要思想:依赖倒置原则。
1、高层模块不应该依赖底层模块,二者都应该依赖抽象 2、抽象不应该依赖细节,细节应该依赖抽象。 3、依赖倒置的中心思想是面向接口编程。 4、依赖倒置原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础搭建的架构要稳定的多。 5、使用接口或抽象类的目的是指定好规范,而不涉及任何具体操作,展现细节的任务交给他们的实现类来完成。
本篇文章主要记录了JUC的四个并发工具类,闭锁CountDownlatch、栅栏CyclicBarrier、信号量Semaphore、交换器Exchanger。CountDownlatch通常用于主线程等待其他任务线程执行完毕的场景;CyclicBarrier主要阻塞当前线程,等待其他线程(大家无论谁先跑到A点,必须要等其他线程也到达了A点,大家才能继续)。信号量Semaphore可以用来控制同时访问特定资源的线程数量(比如100个线程只能有10个线程可以获得MySQL连接)。交换器Exchanger很少用,只适用于两个线程在同步点交换数据的场景(如下图)。
Fork/Join框架就是在必要的情况下,将一个大任务,进行拆分(fork)成若千个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行join汇总。
ForkJoin框架采用工作窃取
模式(work-stealing) :当执行新的任务时它可以将其拆分分成更小的任务执行,并将小任务加到线程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中。
相对于一般的线程池实现,fork/join框架的优势体现在对其中包含的任务的处理方式上,在一般的线程池中,如果一个线程正在执行的任务由于某些原因无法继续运行,那么该线程会处于等待状态。而在fork/join框架实现中,如果某个子问题由于等待另外一个子问题的完成而无法继续运行。那么处理该子问题的线程会主动寻找其他尚未运行的子问题来执行。这种方式减少了线程的等待时间,提高了性能。
本文通过生产者消费者模型主要讲述了什么是虚假唤醒,以及处理处理虚假唤醒。另外还使用了Condition 来控制线程间的通信,Condition接口描述了可能会与锁有关联的条件变量,这些变量在用法上与使用Object.wait 访问的隐式监视器类似,但提供了更强大的功能。需要特别指出的是,单个Lock 可能与多个Condition 对象关联。为了避免兼容性问题,Condition 方法的名称与对应的Object 版本中的不同。 在Condition 对象中,与wait、notify 和notifyAll 方法对应的分别是await、signal 和signalAll。 Condition允许发生虚假唤醒,这通常作为对基础平台语义的让步。不过Condition还是应该总是在一个循环中被等待,避免虚假唤醒的发生。
本文主要讲述了使用线程池的好处,Executors创建的五种线程池特点,简单介绍了Fork/Join框架。围绕Executor框架展开,阐述了线程池的工作流程,探讨了ThreadPoolExecutor的全部构造参数和意义,以及阿里巴巴不推荐使用Executors创建线程池的原因,另外,介绍了我们应该怎么样合理的创建线程池,对于CPU密集型和IO密集型以及混合型的创建方式。探讨了新任务提交后的执行流程,另外简单画了一下线程池生命周期图。
Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或者并发执行任务的程序都可以使用线程池。开发 中使用线程池的三个优点如下: 1、降低资源消耗:通过重复利用已创建的线程降低线程创建和销毁带来的消耗。 2、提高响应速度:当任务到达时,任务可以不需要等待线程创建就能立即执行。 3、提高线程的可管理性:使用线程池可以统一进行线程分配、调度和监控。