03 并发篇

线程有哪些状态

新建、可运行、阻塞、等待、等待(有时限)、终结
image
操作系统层面有物种状态:新建、就绪、运行、终结、阻塞
1.分到CPU时间的:运行
2.可以分到cpu时间的就绪
3.分不到cpu时间的:阻塞

线程池的核心参数(ThreadPoolExecutor)

1.corePoolSize:核心线程数目:最多保留的线程数
2.maximumPoolSize 最大线程数目:核心线程数+救急线程
3.keepAliveTime生存时间:针对救济线程
4.unit时间单位:针对救济线程
5.workQueue:阻塞队列
6.threadFactory线程工厂:可以为线程创建时起个好名字
7.handler:拒绝策略(四种)

sleep vs wait

wait必须在同步代码块中执行
共同点:wait(),wait(long)和sleep(long)的效果都是让当前线程暂时放弃CPU的使用权,进入阻塞状态
方法归属不同:

  1. sleep(long)是Thread的静态方法
  2. wait(),wait(long)都是Object的成员方法,每个对象都有
    醒来时机不同:
  3. 执行sleep(long)和wait(long)的线程都会等待响应毫秒后醒来
  4. wait(long)和wait()还可以被notify唤醒,wait()如果不唤醒就一直等下去
  5. 他们都可以被打断唤醒
    锁特性不同:
  6. wait方法的调用必须先获取wait对象的锁,而sleep则无此限制
  7. wait方法执行后会释放对象锁,允许其它线程获得该对象锁(我放弃,但你们还可以用)
  8. 而sleep如果在synchronized代码块中执行,并不会释放对象锁(我放弃,你们也用不了)

lock vs synchronized

语法层面:
synchronized 是关键字,源码在jvm中,用c++语言实现
Lock是接口,源码由jdk提供,用Java语言实现
使用Synchronized时,退出同步代码块锁会自动释放,而使用Lock时,需要手动调用unlock方法释放锁
功能层面:
二者均属于悲观锁,都具有基本的互斥、同步、锁重入功能
Lock提供了许多synchronized不具备的功能,离离如获取等待状态、公平锁、可打段、可超时、多条件变量
Lock有适合不同场景的实现,如ReentrantLock,ReentrantReadWriteLock
性能方面:
在没有竞争时,synchronized做了很多优化,如偏向锁、轻量级锁,能能不来
在竞争激烈时,Lock的实现通常会提供更好的性能。

volatile是否能保证线程安全

1.线程安全要考虑三个方面:可见性、有序性、原子性
可见性指,一个线程对共享变量修改,另一个线程能看到最新的结果(JIT优化)
有序性:一个线程内代码按编写顺序执行
原子性:一个线程内多行代码以一个整体运行,期间不能有其他线程的代码插队
2.volatile能搞保证共享变量的可见性和有序性,但不能保证原子性

悲观锁 vs 乐观锁

  1. 悲观锁的代表是synmchronized和Lock锁
    1. 其核心思想是线程只有占有了锁,才能去操作共享变量,每次只有一个线程占锁成功,获取锁失败的线程,都得停下来等待
    2. 线程从运行到阻塞、再从阻塞到唤醒,涉及线程上下文切换,如果频繁发生,影响性能
    3. 实际上,线程在获取synchronized和Lock锁 时,如果锁已被占用,都会做几次重试操作,减少阻塞机会
  2. 乐观锁的代表时AtomicInteger,使用cas来保证原子性
    1. 其核心思想是无需加锁,每次只有一个线程能成功修改共享变量,其它失败的线程不需要停止,不断重试直至成功
    2. 由于线程一直运行,不需要阻塞,因此不涉及线程上下文切换
    3. 它需要多核cpu支持,且线程数不应超过cpu核数

Hashtable vs ConcurrentHashMap

1.Hashtable 与 ConcurrentHashMap都是线程安全的Map集合
2.Hashtable并发度低,整个Hashtable对应一把锁,同一时刻,只能由一个线程操作它
3.1.8之前ConcurrentHashMap使用Segment+数组+链表的结构,每个Segment对应一把锁,如果多个线程访问不同的Segment,则不会冲突
4.1.8开始ConcurrentHashMap将数组的每个头节点作为锁,如果多个线程访问的头节点不同,则不会冲突

ApplicationContext refresh的流程(12个方法)

  1. prepareRefresh

    • 这一步创建和准备了Environment对象(主要获取一些键值信息,值注入,StandardEnvironment)
  2. obtainFreshBeanFactory

    • BeanFactory的作用是负责bean的创建、依赖注入和初始化
    • BeanDefinition作为bean的涉及蓝图,规定了bean的特征,如单例多例、依赖关系、初始销毁方法等。
    • BeanDefinition的来源有多种多样,可以是通过xml获得、通过配置类获得、通过组件扫描获得、也可以是编程添加
  3. prepareBeanFactory
    StandardBeanExpressionResolver来解析SpEL
    ResourceEditorRegistrar会注释类型转换器,并应用ApplicationContext提供的Environment完成${}解析
    特殊的bean指beanFactory 以及 ApplicationContext,通过registerResolvableDependency来注册它们

  4. postProcessBeanFactory
    一般Web环境的ApplicationContext都要利用它注册新的Scope,完善Web下的BeanFactory,体现的是模板方法的设计模式

  5. invokBeanFactoryPostProcess
    beanFactory后处理器,充当beanFactory的扩展点,可以用来补充活修改BeanDefinition。ConfigurationClassPostProcessor-解析@Configuration、@Bean、@Import、@PropertySource等。PropertySourcePlaceHolderConfigurer替换BeanDefinition中的${}

  6. registerBeanPostProcess
    bean后处理器,充当bean的扩展点,可以工作再bean的实例化、依赖注入、初始化阶段
    AutowriedAnnotationBeanPostProcessor功能有:解析@Autowired @Value注解
    CommonAnnotationBeanPostProcessor功能有:解析@Resource,@PostConstruct,@PreDestory
    AnnotationAwareAspectJAutoProxyCreator功能有:为复核切点的目标bean自动创建代理

  7. initMessageSource
    实现国际化,容器中一个名为messageSource的bean,如果没有,则提供空的MessageSource实现

  8. initApplicationEventMulticaster
    用来发布事件给监听器,可以从容器中找明为applicationEventMulticaster的bean作为事件广播器,若没有,也会新建默认的事件广播器

  9. onRefresh
    SpringBoot中的子类可以在这里准备WebServer,即内嵌web容器
    体现模板方法的设计模式

  10. registerListeners
    用来接收事件,一部分监听器是事先编程添加的,另一部分监听器来自容器中的bean、还有一部分来自于@EventListener的解析
    实现ApplicationListener接口,重写其中onApplicationEvent(E e)方法即可

  11. finishBeanFactoryInitialization
    conversionService也是一套转换机制,作为对PropertyEditor的补充
    内嵌值解析器用来解析@Value中的${},接用的是Environment的功能
    单例池用来缓存所有单例对象,对象的创建都分三个阶段,每一阶段都有不同的bean后处理器参与进来,扩展功能

  12. finishRefresh
    用来控制容器内需要声明周期管理的bean,如果容器中有名称为lifycycleProcessor的bean就用它,否则创建默认的声明周期管理器,调用context的start,即可出发所有实现lifeCycle接口bean的start
    调用context的stop,即可出发所有实现LifeCycle接口bean的stop

Spring bean的生命周期

阶段一:处理名称,检查缓存
1.先把别名解析为实际名称,再进行后续处理
2.若要FactoryBean本身,需要使用&名称获取
3.singletonObjects是一级缓存,放单例成品对象
4.singletonFactories是三级缓存,放单例工厂
5.earlySingletonObjects是二级缓存,放单例工厂的产品,可称为提前单例对象
阶段二:检查父工厂
* 父子容器的bean名称可以重复
* 优先找子容器的bean,找到了直接返回,找不到继续到父容器找
阶段三:检查DependsOn
阶段四:按Scope创建bean
scope理解为从xxx返回内找到这个bean更贴切
singleton scope表示从单例池返回内获取bean,如果没有,则创建并放入单例池
prototype scope表示从不缓存bean,每次都创建新的
request scope表示从request对象范围内获取bean,如果没有,则创建并放入request..
阶段五:创建bean
阶段六:类型转换
阶段七:销毁bean

posted @ 2023-06-01 21:47  生活的样子就该是那样  阅读(4)  评论(0编辑  收藏  举报