中信银行知识点

 

1.spring ioc  aop

ioc 

2. BeanFactory 和ApplicationContext

ApplicationContext是BeanFactory的子接口,也被称为应用上下文。BeanFactory提供了Spring的配置框架和基本功能,ApplicationContext则添加了更多企业级功能(如国际化的支持),他另一重要优势在于当ApplicationContext容器初始化完成后,容器中所有的 singleton Bean 也都被实例化了,也就是说当你需要使用singleton Bean 是,在应用中无需等待就可以用,而其他BeanFactory接口的实现类,则会延迟到调用 getBean()方法时构造,ApplicationContext的初始化时间会稍长些,调用getBean()是由于Bean已经构造完毕,速度会更快。因此大部分系统都使用ApplicationContext,而只在资源较少的情况下,才考虑使用BeanFactory。

Spring框架中的Bean,或者说组件,获取实例的时候都是默认单例模式,这是在多线程开发的时候需要尤其注意的地方。

 

了解了bean默认是单例模式,不由想spring的单例和设计模式单例同一种吗?其实不一样。单例模式是指在一个JVM进程中仅有一个实例,而Spring单例是指一个Spring Bean容器(ApplicationContext)中仅有一个实例。如果有多个Spring容器,可能有多个Bean对象。

3. bean 初始化过程

  • 实例化;
  • 设置属性值;
  • 如果实现了BeanNameAware接口,调用setBeanName设置Bean的ID或者Name;
  • 如果实现BeanFactoryAware接口,调用setBeanFactory 设置BeanFactory;
  • 如果实现ApplicationContextAware,调用setApplicationContext设置ApplicationContext
  • 调用BeanPostProcessor的预先初始化方法;
  • 调用InitializingBean的afterPropertiesSet()方法;
  • 调用定制init-method方法;
  • 调用BeanPostProcessor的后初始化方法;

4. Mybatis 缓存

一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个(内存区域)数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。

  一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。当一个sqlSession结束后该sqlSession中的一级缓存也就不存在了。Mybatis默认开启一级缓存。

  二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession去操作数据库得到数据会存在二级缓存区域,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

  二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,不同的sqlSession两次执行相同namespace下的sql语句且向sql中传递参数也相同即最终执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。Mybatis默认没有开启二级缓存需要在setting全局参数中配置开启二级缓存

 

5. JVM内存结构

中信银行知识点_第1张图片

这里介绍的是JDK1.8 JVM内存模型。1.8同1.7比,最大的差别就是:元数据区取代了永久代。元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元数据空间并不在虚拟机中,而是使用本地内存

6. 线程实现的三种方式

多线程  实现方式  线程同步
1、继承Thread类实现多线程

2、实现Runnable接口方式实现多线程

3、使用ExecutorService、Callable、Future实现有返回结果的多线程

两种方式区别:

如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。

实现Runnable接口比继承Thread类所具有的优势:

1):适合多个相同的程序代码的线程去处理同一个资源

2):可以避免java中的单继承的限制

3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立

 

7.线程池

为什么使用线程池

  • 降低资源消耗。通过复用已存在的线程和降低线程关闭的次数来尽可能降低系统性能损耗;
  • 提升系统响应速度。通过复用线程,省去创建线程的过程,因此整体上提升了系统的响应速度;
  • 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,因此,需要使用线程池来管理线程。

线程池原理

中信银行知识点_第2张图片

8. wait ,sleep

wait():使一个线程处于等待状态,并且释放所持有的对象的lock。

sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
notifyAll():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争

9.使用特殊域变量(volatile)实现线程同步

适用于线程之间数据共享

在生成汇编代码时会在volatile修饰的共享变量进行写操作的时候会多出Lock前缀的指令(具体的大家可以使用一些工具去看一下,这里我就只把结果说出来)。我们想这个Lock指令肯定有神奇的地方,那么Lock前缀的指令在多核处理器下会发现什么事情了?主要有这两个方面的影响:

  1. 将当前处理器缓存行的数据写回系统内存;
  2. 这个写回内存的操作会使得其他CPU里缓存了该内存地址的数据无效

为了提高处理速度,处理器不直接和内存进行通信,而是先将系统内存的数据读到内部缓存(L1,L2或其他)后再进行操作,但操作完不知道何时会写到内存。如果对声明了volatile的变量进行写操作,JVM就会向处理器发送一条Lock前缀的指令,将这个变量所在缓存行的数据写回到系统内存。但是,就算写回到内存,如果其他处理器缓存的值还是旧的,再执行计算操作就会有问题。所以,在多处理器下,为了保证各个处理器的缓存是一致的,就会实现缓存一致性协议,每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置成无效状态,当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理器缓存里。因此,经过分析我们可以得出如下结论:

  1. Lock前缀的指令会引起处理器缓存写回内存;
  2. 一个处理器的缓存回写到内存会导致其他处理器的缓存失效;
  3. 当处理器发现本地缓存失效后,就会从内存中重读该变量数据,即可以获取当前最新值。

这样针对volatile变量通过这样的机制就使得每个线程都能获得该变量的最新值。

10. ReentrantLock和Synchronized
 

为什么用lock?

我们先来看下死锁产生的四个必要条件:1、互斥:某共享资源一次只允许一个线程占有。2、占有且等待:一个线程本身占有资源(一种或多种),同时还有资源未得到满足,则不会释放已有的资源。3、不可抢占:其他线程不能抢占已被别的线程占有的资源。4、循环等待:线程A等待线程B的资源,线程B等待线程A的资源,这就是循环等待。sychronized可能产生死锁。Lock设计用来破坏第三条,不可抢占

ReentrantLock类是可重入、互斥、实现了Lock接口的锁,它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。

11. happens before

JVM定义的Happens-Before原则是一组偏序关系:对于两个操作A和B,这两个操作可以在不同的线程中执行。如果A Happens-Before B,那么可以保证,当A操作执行完后,A操作的执行结果对B操作是可见的

/**
 *《Java并发编程实战》27页程序清单3-1
 */
public class NoVisibility {
    private static boolean ready; 
    private static int number;
    
    private static class ReaderThread extends Thread {
        public void run() {
            while(!ready) {
                Thread.yield();
            }
            System.out.println(number);
        }
    }
    
    public static void main(String[] args) {
        new ReaderThread().start(); //启动一个线程
        number = 42;
        ready = true;
    }
}

上面的代码中,主线程和读线程都访问共享变量ready和number。程序看起来会输出42,但事实上很可能会输出0,或者根本无法终止。这是因为上面的程序缺少线程间变量可见性的保证,所以在主线程中写入的变量值,可能无法被读线程感知到。

12 线程同步的方式

  • synchronize和lock
  • wait notify
  • 同步工具类,countdownlatch,cylinc barrier
  • volatile
  • threadlocal
  • blockingqueue
  • 使用原子变量实现线程同步

13 Spring  cloud和微服务架构

,微服务架构是—种架构模式或者说是一种架构风格,它提倡将单一应用程序划分成-一组小的服务,每个服务运行在其独立的自己的进程中,服务之间互相协调、互相配合,为用户提供最终价值。服务之间采用轻量级的通信机制互相沟通(通常是基于HTTP的REST ful API)。毎个服务都围绕着貝体业务进行构建,并且能够被独立地部罟到生产环境、类生产环境等另外,应尽量避免统一的、集中式的服务管理机制,对具体的_个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建,可以有一个非常轻量级的集中式管理来协调这些服务,可以使用不同的语言来编写服务,也可以使用不同的数据存储
 

与doubbo的区别

本质区别: 

dubbo 是 基于 RPC 远程 过程调用 

cloud 是基于 http  rest api 调用

中信银行知识点_第3张图片

最大区别: Spring Cloudi抛弃了 Dubbo的RPC通信,采用的是基于HTP的REST方式。

严格来说,这两种方式各有优劣。虽然从一定程度上来说,后者牺牲了服务调用的性能,但也避兔了上面提到的原生RPC带来的问题。

而且REST相比RPC(基于RPC协议利用socket传输)更为灵活,服务提供方和调用方的依赖只依靠一纸契约,不存在代码级别的强依赖,这在强调快速演化的微服务环境下,显得更加合适 
 

14 Spring cloud用了那些组件

  • Spring cloud eruke
  • Spring cloud feign
  • Spring boot
  • Spring sleuth
  • spring cloud consul

15 SQL优化

 

  • 建立索引在查询字段
  • 注意索引数目不要过多
  • 防止索引失效的情况,比如不等于,null判断,or连接(应该用union),最左匹配,

1.对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。

2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描

3.应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描

4.应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描,如:

select idfrom twhere num=10 or Name= 'admin'

可以这样查询:

select idfrom twhere num= 10union allselect idfrom twhere Name= 'admin'

或者全部建立索引

5. 最左匹配

这也是最左前缀原理的一部分,索引index1:(a,b,c),只会走a、a,b、a,b,c 三种类型的查询,其实这里说的有一点问题,a,c也走,但是只走a字段索引,不会走c字段。如果b是范围查询,则c的索引不会走

6.mysql中like查询是以%开头,索引会失效变成全表扫描,覆盖索引

7. 如果mysql使用全表扫描要比使用索引快,则不会使用到索引

8 慢查询日志,slow query log.命令是explain

https://blog.csdn.net/why15732625998/article/details/80388236

16 JDK1.8 新特性

  • default关键字,接口可以有方法实现
  • lambda表达式:函数式编程

  • 函数式接口

  • Stream

  • JVM

 

 

 

你可能感兴趣的:(中信银行知识点)