2021随记

一  @autowired和@resource的区别总结:

   @autowired 由Spring提供,默认按照byType注入,可以和@Qualifier 注解配套使用,用来区分多个相同的bean实例

  1. @Autowired   
  2. @Qualifier("userServiceImpl")   
  3. public IUserService userService;

  @resource 由jdk提供,默认按照byName注入

   在使用@Autowired注解之前需要在Spring配置文件进行配置,<context:annotation-config />,开启注解装配;


二 前后端参数交互相关:

 1 Post请求 前端可以是Json字符串

    ( 1): 直接获取request    如: public String getHtml(HttpServletRequest request) {}

     (2): 使用@RequestBody 可接受的参数 String, Map,JSONObject,或者对应的JavaBean

 2 Get请求   (url后拼接参数的url+?)

    (1) 直接获取request    如: public String getHtml(HttpServletRequest request) {}

    (2) 什么也不加,直接在方法中获取参数值   如: public String getHtml(String url, String token) {}

    (3) 利用@RequestParam    如: public User getUserInfo(@RequestParam(value = "url",required = false) String url){}   

  3  @RequestParam在请求类型post/get/delete中都可以使用 ,content-type 必须是www-form形式


三:线程不安全的类有哪些

   1  Stringbulider(StringBuffer):append方法里面有三克拉关键字保证并发安全

      

  2 SimpleDateFormat(LockDate)  :可以通过ThreadLocal 保证安全

  3 ArrayList(CopyONWriteArrayList  / collections.synchronizedList ) , LinkList(ConcurentLinkQueue)  :

    多线程操作ArrayList 会报 ConcurrentModificationException,这个异常是基于 fast-fail 机制的

  注 :CopyaONWriteArrayList (读写分离+ap)

  4 HashMap  (Hashtable)


四: 基础随记

  1 包装类型和基本类型(包装类型特性更多,如hashMap存值需要包装类型)

       区别: 包装类型使用new关键字 、存储在堆和栈、初始默认值不同

       Java提供了自动拆箱与自动装箱功能。    Integer i =10; //自动装箱   int b= i; //自动拆箱


  2 自定义注解

   元注解(@Retention、@Target、@Document、@Inherited)+  @interface

  通过反射区获取类的信息  Class clazz = Class.forName("tyidc.common")  / new一个类对象,然后 com.getClass  /  直接Class clazz = common.class


五 集合类

   1 ArrayList 和 LinkedList 

       查询用前者,增删用后者(只需要记录前后向);因为Array底层是数组结构,增删会影响其他数组的下标;Linked是线性的结构,查询需要依次查找效率低

      ArrayList底层(连续排列)

        它底层是一个动态数组,随着数据的增加会自动扩容(array.copyof),add元素的时候,是从头部依次向后添加,超过默认的size()=10的长度后,会创建

        一个长度为当前长度1.5倍的新数组,当前数组元素复制到新数组后释放当前数组内存数据。

     LinkedList底层(分布不均匀)

       它是一个双向链表的形式,是由3个部分组成(prev、data、next.),结构如下图  ,在插入和删除的时候 ,只需要修改相邻元素的prev和next的值。    

    Vector:使用了 Synchronized 来实现线程同步,线程安全,扩容是2倍,逐渐被弃用:1是因为它的方法基本都加了同步,单线程操作会大大减低效率,2有替代品

2 HashMap(无序,不可重复)

 hashmap

  存取元素:hashcode() + equals()  数组+链表+红黑树

红黑树
红黑树

       通过调用key值的hashcode方法计算出哈希值,哈希算法装换成数组的index下标,如果数组没有此下标,就直接存,取值就为null,下标对应的是链表的话

       存取原理一致;存的第一步是判空,再去计算hash

  扩容(resize):

  默认的容量是16,默认的加载因子是0.75 ,当元素超过12 (YU值 第四声) 时候,会触发扩容(指定长度为原来的2倍)

3 ConcurrentHashMap (分段锁)

   对整个数组进行了分段,每段上加入了lock锁进行保护,多线程情况下可以替换hashTable

   与hashmap除了线程安全的区别外还有不能为空,它可以是hashmap和hashtable的结合

 原理:相对于1.7 它多了红黑树+CAS+三克拉

  

六:多线程并发编程(原子、可见性、有序)

 1 基本概念

   线程与进程:一个进程下的多个线程共线进程中的资源,单个线程互不影响

   上下文切换:线程在分配时间片内占用CPU执行任务,使用完时间片后,就会处于就绪状态并让出CPU让其它线程占用,这就是上下文切换。

  run()和start() :  new 一个 Thread,线程进入了新建状态。调用 start() 方法,会启动一个线程并使线程进入了就绪状态(就绪状态是到运行状态的唯一入口),当分配到时间                            片后就可以开始运行了。 start() 会执行线程的相应准备工作,然后自动执行 run() 方法的内容,这是真正的多线程工作。

  interrupt()是给线程设置中断标志;interrupted()是检测当前线程中断并清除中断状态;isInterrupted()只检测中断

  wait与notify: 调用任意对象的 wait()方法都将导致线程阻塞,阻塞的同时也将释放该对象的锁,调用notify(),也需要重新获取锁;wait、notify 方法必须在                                                synchronized块  或方法中被调用。

  finalize():GC回收某个对象时候,会先调用此对线的finalize()方法,下一次回收时候才真正回收

                         

2 创建线程

  (1)继承Thread类,重写run方法(因为是继承,获取Thread实例后,直接.start)

    (2)   实现Runable接口,实现run方法(Thread内的对象才是线程对象)

           

  (3)实现Callable接口,重写call方法(又返回+内部可以try catch捕获异常,多一步创建FutureTask,并且以它为参数创建Thread对象)

  (4)线程池方式

         

 3 synchronized (原子、可见、有序)

   Synchronized应用在方法上时,在字节码中是通过方法的AccCC_Synchronized标志来实现的,

   Synchronized应用在同步块上时,在字节码中是通过Monitorenter和    Monitorexit(2次 第二次是异常时候释放锁)实现的,相应的对monitor对象 +1 和 -1

  

4 lock (结合try+catch使用 在finally中手动释放锁 unlock())

  特性:多个线程读共享资源不会发生冲突,知道有没有成功获取锁,是一个接口

 读写锁ReentrantReadWriteLock: 实现一个用户写 多个用户读。它表示有两个锁(readlock和writelock),一个是读操作相关的锁,也称为共享锁;另一个是写操作相关的                锁,也叫排他锁。“读 写”、“写读”、和 “写写“ 都是互斥的;而 ”读读“ 是异步的,非互斥的

5 AQS 

ReentrantLock内部包含了一个AQS对象:

很简单,这个AQS对象内部有一个核心的变量叫做state,是int类型的,代表了加锁的状态

初始状态下,这个state的值是0。

另外,这个AQS内部还有一个关键变量,用来记录当前加锁的是哪个线程

AQS就是一个并发包的基础组件,用来实现各种锁,各种同步组件的。

它包含了state变量、加锁线程、等待队列等并发中的核心组件。 

6 线程实现定时的小例子(sleep实现):

   


七:JVM相关

作用 : 一个java文件通过反编译转化为 .class文件,通过类加载器将类的 class文件中的二进制数据读到内存,放在方法区,然后在堆中创建一个class对象(分配内存)

     

   1 队列和栈 :队列是FIFO 先进先出 ,栈是LFIO后进先出

   2 内存泄漏与溢出( 通常情况下,内存泄漏的堆积导致内存溢出)

    泄漏:申请内存后,无法释放内存空间

            比如:把一些对象的引用加入到了集合容器(比如ArrayList)中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大,用完之                         后应该及时的clear()掉

    溢出:申请内存时,没有空间了,或者是在int存储空间存储Long类型的数据,也会OOM。

             原因:一次从库里面去的数据量过大,对对象的引用未能及时清空,循环创建实例,内存值设置过小

             解决:集成工具eclipse的话,在eclipse的根目录找到eclipse.ini文件,编辑里面的 -- xmx参数,增大内存

            优化方案:

                   1.检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线                                   前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。

                   2.检查代码中是否有死循环或递归调用。

                   3.检查是否有大循环重复产生新对象实体。

                   4.检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。

  3   GC回收:

       Java 提供的 GC 功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的

       针对java堆中的新生代(eden+2个survivor)和老年代(占比2/3) ;对象在新生代的Eden出现,经历一次minorGc,存入survor中,16次之后 到老年代 在fullGc

     1 垃圾收集器:

     标记整理算法:G1 垃圾收集器,把有用的和没用的各放到一起,不限新生和老年代

     标记清除算法:CMS垃圾收集器为例,先标记出可以回收的,再回收被标记的,发生在老年代中,会产生内存碎片;在启动 JVM 的参数加上

                           “- XX:+UseConcMarkSweepGC”来指定使用CMS垃圾回收器,

      2 类加载机制和过程(java文件 - class文件 - 堆中分配内存 - 解析 - 初始化 )

           把描述类的数据从Class文件加载到内存,并对数据进行校验,解析和初始化,最终形成可以被虚拟机直接使用的java类型。

         类的加载器分类:

     

        双亲委派:子类加载器、收到类加载需求时候,不会自己先去加载这个类,而是将其委派给父类加载器,由父类去加载,如果此时父类不能加载,反馈给子类,由子类                             去完成类的加载   --  bootStrapClassLoader是加载器的顶级节点

                 作用:防止加载器重复加载想用的class文件,所以要先去询问父类加载器

   JVM调优的参数有哪些:堆栈的值设置(Xms/Xmx);

                                           新生代中的Eden和Surviver的比例(XX:SurvivorRatio=8 /  8:2);

                                           新生代和老年代的比例(-XX:NewRatio=4  / 1:4)

                                           可以指定垃圾收集器的组合

               

八:Spring相关

    1 spring 容器和spring 上下文理解

      把对象创建、管理的控制权都交给Spring容器,这是一种控制权的反转,所以Spring容器才能称为IOC容器---空间

     上下文就是帮我们把管理的对象注册到容器中的一种容器对象

   2  IOC  管理对象的创建,生命周期,装配,我们只需要在xml里面配置好相应的对象以及对象之间的依赖关系。

       实现:工厂模式+反射

   3 AOP

            aspect(切面):切入点+通知————通知(Advice)说明了干什么的内容(即方法体代码)和什么时候干(什么时候通过方法名中的before,after,around等就能知道),                                   切入点说明了在哪干(指定到底是哪个方法)

           先定义切入点和通知(userService和MyAdvice)--pointcut和aspsct

   

  4 springMVC的工作流程(q=前端控制器DispatcherServlet,是整个相应的控制中心)
     用户请求--q--处理器找到那个controller可以解决--q--下发给对应的control执行--返回执行后的modelandView--q--交给视图处理器--页面和用户


九 Spring boot  

 1 Spring 下的一个子项目,提供了各种启动器,简化了Spring的难度也简略了Spring繁琐的配置

 2  自动装配的原理(几个核心注解)

标题自动装配原理图

    自动配置的核心注解是@SpringBootApplication,该注解是spring boot的启动类注解,它是一个复合注解

(1)@SpringBootConfiguration:该注解上有一个 @Configuration注解,表示这个spring boot启动类是一个配置类

(2)@EnableAutoConfiguration:表示开启自动配置,它也是一个复合注解,里面包含:

@AutoConfigurationPackage,该注解里面上有一个@Import(AutoConfigurationPackages.Registrar.class)注解,其中 Registrar 类的作用是将启动类所在包下的所有              子包的组件扫描注入到spring容器中

@Import(AutoConfigurationImportSelector.class):其中AutoConfigurationImportSelector类中有一个getCandidateConfigurations()方法,该方法通过                                        SpringFactoriesLoader.loadFactoryNames()方法查找位于META-INF/spring.factories文件(文件位置在这个jar包里面)中的所有自动配置类,并加载这些类   
             这个spring.factories文件也是key=value的形式,其中一个key是EnableAutoConfiguration类的全类名,而它的value是一个xxxxAutoConfiguration的类名的列表

   接下来是 Spring.factories文件(JavaConfig形式的Spring容器配置类)里面自动配置类如何生效:通过@ConditionOnxxx注解实现的

 3 定时任务

在 Spring Boot 中使用定时任务主要有两种不同的方式,一个就是使用 Spring 中的 @Scheduled 注解,另一个则是使用第三方框架 Quartz。

使用 Spring 中的 @Scheduled(思凯救得) 的方式主要通过 @Scheduled 注解来实现。

使用 Quartz ,则按照 Quartz 的方式,定义 Job 和 Trigger 即可。


 4  boot 集成mybatis

 添加mybatis的启动依赖  mybatis-spring-boot-starter 1.2.0  ;  在mybatis的DAO层(接口)中 添加@Mapper注解   ;在application.yml配置数据源信息


十:Spring Cloud 

     

是基于SpringBoot的一整套实现微服务的框架。它提供了各个微服务开发所需的配置管理、负载均衡、服务发现、断路器等组件

1 Eureka (注册中心)

 (1) eureka是基于ap的:可用性,eureka节点都是平等的,一个挂了不影响服务调用,只是可能 数据不是最新的(不是最新的就是自我保护机制导致的)。

         zookeeper是基于cp的:一致性,节点挂了 重新leader选举,选举时间内不可用

 (2) 自我保护机制:当Eureka Server节点在短时间内丢失过多的客户端时(可能发送了网络故障),那么这个节点将进入自我保护模式(保护注册表中的信息),不再注             销任何微服务,当网络故障回复后,该节点会自动退出自我保护模式

2   负载均衡的方法(Ribbon、Nginx)

  (1)轮询策略:6个请求 3个服务器(Nginx/ Ribbon)

                   顺序轮询:3个服务器分别处理2个请求 ,第一台机器接受1 和 4 的请求

                   加权轮询:给服务器分配优先级{4:1:1},第一台机器处理1、2、3、4 请求,

         (Nginx默认的就是改进的加权轮询策略)当请求来时,不会集中落在优先级较高的机器上;给服务器分配优先级{4:1:1}  结果:1、2、4、6(具体算法没明白)

  (2) 随机策略:随机分配,不集中一台机器(dubbo)

  (3)ip-hash 哈希策略:hash函数设置合理负载相对均衡+相同的请求hui会落在同一个节点中;缺点就是宕机了就出问题(redis)

   Ribbon:客户端负载均衡,从注册中心读取后采用轮询策略访问服务,开启客户端负载均衡的注解@LoadBalanced注解

3 Hystrix(断路器)保护服务的作用,友好返回,避免单个引发整体

  服务调用过程中断网了怎么办,Hystrix就是防止这情况带来异常问题的一个工具,具有服务降级,服务熔断,监控等防止雪崩(大量请求某个服务器宕机影响项目)的技术

十一:Mybatis相关

   半自动的ORM持久层框架,sql与代码分离,自动将java对象映射成sql语句,自动将sql结果集映射成java对象,代码量少

1 原理:mybatis应用程序通过SqlSessionFactoryBuilder从mybatis-config.xml配置文件中构建出SqlSessionFactory,(从xml中构建factory)

             然后,SqlSessionFactory的实例直接开启一个SqlSession,(从factory中构建sqlsesson)

             再通过SqlSession实例获得Mapper对象并运行Mapper映射的SQL语句,完成对数据库的CRUD和事务提交,(sqlsesson--mapper对象)

             之后关闭SqlSession。

2 #{}和${}的区别

  #{} 占位符,参数是字符串形式,预编译处理时候将sql中的#{}替换成 ?号,变量替换后会默认加上 ‘’ 符号,有效防止sql注入

  ${} 拼接符,参数传递时候,是原值传入  

十二:Redis (原子性)

1 redis中的过期删除策略:Redis是key-value数据库,我们可以设置Redis中缓存的key的过期时间。Redis的过期策略就是处理Redis中缓存的key过期

    通过expire来设置key 的过期时间:采用的是定期+惰性 

  (1)定时过期 :设置key值的过期时间,到时间就清除

  (2)惰性过去:访问具体key值时候,才会去判断key值有没有过期,过期了就删除,重新查,再存进来

  (3)定期过期:每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案

2 redis 淘汰策略(6种):Redis内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。(可以保障热点数据)

 (1)从已设置过期时间的数据集的淘汰  使用少的  / 快过期的 / 任意

 (2)从数据集淘汰 使用少的 / 任意  (常用)     + 永不过期策略 

3  Redis分布式锁(单独线程管控不同网络)--下面分布式锁中有更详细的内容

先拿setnx()来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。可以同时把setnx 和expire合成一条指令来用的

jedis.set(String key, String value, String nx, String expx, int time)

4 一个简单的hash例子

5 与Memcached比较

  • memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型
  • redis的速度比memcached快很多
  • redis可以持久化其数据

十二:dubbo(服务注册,负载均衡(随机策略),集群容错)

 阿里开源的RPC(远程调用)分布式框架,,服务者和消费者都在dubbo上注册。

1 dubbo 各个节点

       Provider: 暴露服务的服务提供方。   Consumer: 调用远程服务的服务消费方。

       Registry: 服务注册与发现的注册中心。 Monitor: 统计服务的调用次调和调用时间的监控中心。  Container: 服务运行容器。

     过程:生产者向注册中心注册服务 -- 消费者向注册中心订阅服务 -- 注册中心向消费者返回服务列表-- 通过dubbo负载均衡去决定具体那个服务 -- 定时将动作(服务的调                   用次数和时间)推送给监控中心

2 dubbo的负载均衡

  默认是随机 还有 轮询 +hash一致 + 最少活跃数调用(目的是让更慢的机器收到更少的请求)

3 dubbo的容错机制

 默认是快速自定切换(fastover) :失败重试其他服务器 ,还有 快速失败:一次调用 失败就报错,失败安全:失败忽略,用于日志记录等

十三:分布式相关

1 秒杀系统思路

 前端:按钮置灰,定时请求

 服务器:nginx和redis都做集群设置

 限流:把秒杀的指令先放入redis,可先从redis里面获取数据,获取到了再去数据库处理

 消息件:把请求先放入mq中,再从队列中获取请求

  熔断:以防万一,做个熔断降级。(集成Sentinel,在需要进行熔断降级的方法上添加@SentinelResource(value = “pay”)注解。)

2 分布式幂等

  唯一Id: 每次操作都根据业务内容生成一个唯一Id(第一次肯定不会重复),每次请求先去判断这个ID有无存在

  生产者一个服务对应的token接口,消费者调用服务时候先去获取这个token,消费完则销毁

 去重表:把业务唯一标识存到表里,每次调判断这个唯一标识

 版本和状态控制

3 分布式锁(基于zk 和 redis + 数据库):加锁保证只有一个客户端对共享资源进行操作,常说的幂等

 1 基于数据库实现分布式锁(建表+服务方法名为字段+字段唯一索引)

    在数据库中创建一个表,表中包含方法名等字段,并在方法名字段上创建唯一索引,想要执行某个方法,就使用这个方法名向表中插入数据,成功插入则获取锁,执行完        成后删除对应的行数据释放锁,插入成功和删除成功代表获取锁和释放锁的步骤。

  对数据库要求较高,多机部署 数据同步 主备切换;需要循环获获取逻辑支撑;

2 基于redis实现分布式锁

 (1)加锁:就是给redis的key设置一个唯一值,并且给一个过期时间 :SET lock_key random_value NX PX 5000  ;命令执行成功则成功获取锁

   random_value 是客户端生成的唯一的字符串。
   NX 代表只在键不存在时,才对键进行设置操作。
   PX 5000 设置键的过期时间为5000毫秒  

 (2)解锁:根据唯一值判断,并且将key对应的唯一字符删除 

        LUA脚本可以来实现:当前字符串(random_value )与目标字符串比较,相同则删除

if redis.call('get',KEYS[1]) == ARGV[1] then 
   return redis.call('del',KEYS[1]) 
else
   return 0 
end

 (3)具体实现 :1分别 写 一个获取锁的方法和一个释放所得方法 2 再具体的业务里面去调这个2个方法 如下

    ---  获取锁的方法 lock()+ jedis.set(唯一字符,NX,过期时间) +结果是 “ok” 

   --- 释放锁的方法 unLock()+ jedis.eval(LUA脚本) +结果是“1”

  ---- 业务调用 :多线程对一个值进行 ++ ,加之前调用lock获取锁,之后调用unlock释放 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值