SpringIOC原理与应用
ICO容器的结构如上图所示,首先要让IOC容器去读取Bean的配置信息,并在容器中生成一份相应的Bean定义注册表,根据这张注册表去实例化Bean,装配好Bean之间的依赖关系,为上层提供准备就绪的环境,Spring提供一个配置文件描述Bean还有Bean之间的依赖关系,利用Java语言的反射功能实例化Bean并建立Bean之间的依赖关系。
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、提高线程的可管理性:使用线程池可以统一进行线程分配、调度和监控。
我们在使用锁时,线程获取锁是一种悲观锁策略,即假设每一次执行临界区代码都会产生冲突, 所以当前线程获取到锁的时候同时也会阻塞其他线程获取该锁。而CAS操作(又称为无锁操作)是一种乐观锁策略,它假设所有线程访问共享资源的时候不会出现冲突,既然不会出现冲突自然而然就不会阻塞其他线程的操作。因此,线程就不会出现阻塞停顿的状态。那么,如果出现冲突了怎么办?无锁操作是使用CAS(compare and swap)又叫做比较交换来鉴别线程是否出现冲突,出现冲突就重试当前操作直到没有冲突为止。
synchronized和ReentrantLock的区别
先说说synchronized和ReentrantLock的区别吧,AQS的分析得等两天了:
1、ReentrantLock (再入锁),位于java.util.concurrent.locks包 2、和CountDownLatch、Future Task、Semaphore一样基于AQS实现 3、能够实现比synchronized更细粒度的控制,如控制公平与非公平 4、调用lock()之后,必须调用unlock()释放锁 5、性能未必比synchronized高,并且也是可重入的 6、synchronized是关键字,ReentrantLock是类 7、ReentrantLock可以对获取锁的等待时间进行设置,避免死锁的发生 8、ReentrantLock可以获取各种锁的信息 9、ReentrantLock可以灵活地实现多路通知 10、机制:sync操作Mark Word,lock调用Unsafe类的park()方法