访问修饰符:
非访问修饰符:
【eg】:
在Java中 ++i、i++并不是线程安全的,要想线程安全,就用使用volatile修饰符完善的AtomicInteger
归类总结为:加载、链接、初始化
连接过程包括 验证,准备、解析三个阶段
【加载】:指的是把class字节码文件从各个来源通过类加载器装载入内存中。
【字节码来源】:一般的加载来源包括从本地路径下编译生成的.class文件,从jar包中的.class文件,从远程网络,以及动态代理实时编译
【类加载器】:一般包括启动类加载器,扩展类加载器,应用类加载器,以及用户的自定义类加载器。
【验证】:保证加载进来的字节流符合虚拟机规范,不会造成安全错误
【准备】:主要是为类变量(注意,不是实例变量)分配内存,并且赋予初值。
【解析】:将常量池内的符号引用替换为直接引用的过程。
符号引用。即一个字符串,但是这个字符串给出了一些能够唯一性识别一个方法,一个变量,一个类的相关信息,直接引用。可以理解为一个内存地址,或者一个偏移量。比如类方法,类变量的直接引用是指向方法区的指针;
而实例方法,实例变量的直接引用则是从实例的头指针开始算起到这个实例变量位置的偏移量
【初始化】:主要是对类变量初始化,是执行类构造器的过程,另说只对static修饰的变量或语句进行初始化
可以参考如下图:
当初始化完成后,就可以使用了,在使用完之后,会在方法区GC的过程中对其进行卸载。至此Java的的整合生命周期也完成。参考
关于Map的算法分析
多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的。
一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销。
Java 三种创建线程的方法:
通过实现 Runnable 接口;
通过继承 Thread 类本身;
通过 Callable 和 Future 创建线程。
JVM是Java Virtual Machine的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
Java语言的一个非常重要的特点就是与平台的无关性。而使用JVM是实现这一特点的关键。
Java语言使用jvm屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在jvm上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。这就是Java的能够“一次编译,到处运行”的原因。
如图
JVM在它的生存周期中有一个明确的任务,那就是运行Java程序,因此当Java程序启动的时候,就产生JVM的一个实例;当程序运行结束的时候,该实例也跟着消失了。下面我们从JVM的体系结构和它的运行过程这两个方面来对它进行比较深入的研究。
JVM都包含:堆内存、栈内存、方法区、本地方法栈、指令计数器及其他隐含寄存器
【堆内存】:所有通过new创建的对象和数组的内存都在堆中分配,堆内存中的实体不再被应用时,JVM启动垃圾回收机制,自动清除,是GC的主要区域,同样是线程共享的内存区域。堆被所有线程共享,堆区中不存放基本类型和对象引用,只存放对象本身。
其大小可以通过-Xmx和-Xms来控制
【栈内存】:栈内存保存基本数据类型、局部变量,对象的引用变量都是在栈内存中的。栈内存中的数据,没有默认初始化值,用完就消失。
【方法区】:保存方法代码(编译后的java代码)和符号表;存放要加载的类信息、静态变量、final类型的常量、属性和方法信息。类信息是由类加载器从类文件中提取出来的。
JVM用持久代(Permanet Generation)来存放方法区,可通过-XX:PermSize和-XX:MaxPermSize来指定最小值和最大值。
【本地方法栈】:用于支持native方法的执行,存储了每个native方法调用的状态。
结构示意图如下:
GC是垃圾收集的意思,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显式操作方法。GC可以有效的防止内存泄露,提高可使用的内存的使用效率。
在HotSpot虚拟机中,主要有:
Minor GC:新生代GC,指发生在新生代的垃圾收集动作,所有的Minor GC都会触发全世界的暂停(stop-the-world),停止应用程序的线程,不过这个过程非常短暂。
Major GC/Full GC:老年代GC,指发生在老年代的GC。
Java堆是被所有线程共享的一块内存区域,所有对象实例和数组都在堆上进行内存分配。为了进行高效的垃圾回收,虚拟机把堆内存划分成新生代(Young Generation)、老年代(Old Generation)和永久代(Permanent Generation)3个区域。
JVM针对新生代,主要采用复制算。针对老年代,通常采用标记-清除算法或者标记-整理算法来进行回收。
【复制算法】:新生代由 Eden 与 Survivor Space(S0,S1)构成,Survivor 幸存区是将内存分成大小相等的两块区域,每次使用其中的一块。当这一块的内存用完了,就将还存活的对象复制到另一块区域上,然后对该块进行内存回收。大小通过-Xmn参数指定,Eden 与 Survivor Space 的内存大小比例默认为8:1,可以通过-XX:SurvivorRatio 参数指定,比如新生代为10M 时,Eden分配8M,S0和S1各分配1M
【标记算法】:老年代对象存活的时间比较长、比较稳定,因此采用标记(Mark)算法来进行回收,所谓标记就是扫描出存活的对象,然后再进行回收未被标记的对象,回收后对用空出的空间要么进行合并、要么标记出来便于下次进行分配,目的就是要减少内存碎片带来的效率损耗。
老年代的空间大小即-Xmx 与-Xmn 两个参数之差,用于存放经过几次Minor GC之后依旧存活的对象。当老年代的空间不足时,会触发Major GC/Full GC。
说明:事实证明,90%以上的新生代对象存活时间很短暂。使用复制算法实现简单,运行效率高,坏处是每次只能使用一半内存,内存的利用率不高;
标记整理算法,涉及两个过程,运行效率慢,且整理之后会产生不连续的内存空间
JVM参数调优
【Lambda 表达式】 − Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中。
【方法引用】 − 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
【默认方法】 − 默认方法就是一个在接口里面有了一个实现的方法。
【Stream API】 −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
【Date Time API】 − 加强对日期与时间的处理。
【Optional 类】 − Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
【Base64编码】内置了 Base64 编码的编码器和解码器。
【Nashorn, JavaScript 引擎】 − Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。
Java8新特新
Java9新特性
spring的核心是一个轻量级的容器(Container),它是实现IoC(Inversion of Control)容器和非侵入性(No intrusive)的框架,并提供AOP(Aspect-oriented Programming)的实现方式,提供对持久层(Persistence)、事务(Transcation)的支持;提供MVC Web框架的实现,并对一些常用的企业服务API提供了一致的模型封装,是一个全方位的应用程序框架,除此之外,对现存的各种框架(Structs、JSF、hibernate、Ibatis、Webwork等),Spring也提供了与他们相整合的方案。
【细节列表】:
1、Spring的核心是一个轻量级(Lightweight)的容器(Container)。
2、Spring是实现IoC(Inversion of Control)容器和非入侵性(No intrusive)的框架。
3、Spring提供AOP(Aspect-oriented programming)的实现方式,把应用业务逻辑和系统服务分开。
4、Spring提供对持久层(Persistence)、事物(Transcation)的支持。
5、Spring供MVC Web框架的实现,并对一些常用的企业服务API(Application Interface)提供一致的模型封装。
6、Spring提供了对现存的各种框架(Structs、JSF、Hibernate、Ibatis、Webwork等)相整合的方案。
总之,Spring是一个全方位的应用程序框架。
【控制反转/IoC】:指的是程序中的一些对象或者变量的控制权,在传统的程序中都是由应用程序自己控制对象创建或者变量赋值,这是一种主动式的控制,导致组件之间的完全耦合;现在将一些对象或者变量的创建控制权交给一个叫做Ioc容器的东西,由这个容器来控制应用程序中所需要的资源,这样就变成了被动的控制,对组件之间的关系进行解耦,所以所谓的反转就是将控制权由应用程序转交到Ioc容器。
【依赖注入/DI】:注入就是IoC容器向应用程序中进行注入应用程序所需要的资源,由应用程序主动装配对象的依赖变应用程序被动接受依赖,所以IoC容器也叫DI容器
【AOP(面向切面编程)】:将具体的通用的应用从业务逻辑中分离出来,各自做各自专业的事情。
(1)创建一个上下文context = createApplicationContext;
(2)context中都会有一个BeanFactory(默认是DefaultListableBeanFactory),在该类的子类类xmlBeanFactory中进行xml文件的解析;
(3)在类XmlBeanDefinitionParser 中用Dom解析xml文件(DefaultXmlBeanDefinitionParser),解析xml文件中所有bean,并将bean放到BeanDefinitionHolder中,封装成BeanDefinition;
(4)再进行bean的注册,具体在BeanDefinitionReaderUtils类调用DefaultListableBeanFactory类的registerBeanDefinition进行bean的注册,在这里用了一HashMap存放bean,其中用Beanname作为键值,其封装好的beanDefinition作为值。还有用一个List存放所有的bean的名字
【no】: spring默认的设置,在该设置下自动装配是关闭的,开发者需要在配置文件中用标签明确依赖关系;
【byName】: 该选项可以根据bean名称设置依赖关系。当向一个bean中自动装配一个属性时,容器将根据bean的名称自动在在配置文件中查询一个匹配的bean。如果找到的话,就装配这个属性,如果没找到的话就报错。
【byType】: 该选项可以根据bean类型设置依赖关系。当向一个bean中自动装配一个属性时,容器将根据bean的类型自动在在配置文件中查询一个匹配的bean。如果找到的话,就装配这个属性,如果没找到的话就报错。
【constructor】: 构造器自动装载,仅仅适用于与有构造器相同参数的bean,如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。
【autodetect】: 该模式自动探测使用构造器自动装配或者byType自动装配。先尝试找合适的带参数的构造函数,若没有则自动选择byType的自动装配模式。
基于注解的自动装配,spring默认是关闭注解模式的,所以需要在配置文件中设置
propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。
propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作
1.【工厂模式】在各种BeanFactory以及ApplicationContext创建中都用到了;
2.【模版模式】各种BeanFactory以及ApplicationContext实现中也都用到了;
3.【代理模式】在Aop实现中用到了JDK的动态代理;
4.【单例模式,这个比如在创建bean的时候。
5.【Tomcat中有很多场景都使用到了外观模式,因为Tomcat中有很多不同的组件,每个组件需要相互通信,但又不能将自己内部数据过多地暴露给其他组件。用外观模式隔离数据是个很好的方法。
6.【策略模式】Comparator这个接口简直就是为策略模式而生的。Comparable和Comparator的区别一文中,详细讲了Comparator的使用。比方说Collections里面有一个sort方法,因为集合里面的元素有可能是复合对象,复合对象并不像基本数据类型,可以根据大小排序,复合对象怎么排序呢?基于这个问题考虑,Java要求如果定义的复合对象要有排序的功能,就自行实现Comparable接口或Comparator接口.
7.【原型模式】:使用原型模式创建对象比直接new一个对象在性能上好得多,因为Object类的clone()方法是一个native方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。
8.【迭代器模式】:Iterable接口和Iterator接口 这两个都是迭代相关的接口,可以这么认为,实现了Iterable接口,则表示某个对象是可被迭代的;Iterator接口相当于是一个迭代器,实现了Iterator接口,等于具体定义了这个可被迭代的对象时如何进行迭代的
资料
Spring MVC 提供了一种分离式的方法来开发 Web 应用。通过运用像 DispatcherServelet,MoudlAndView 和 ViewResolver 等一些简单的概念,开发 Web 应用将会变的非常简单。
Spring Boot 是 Spring 开源组织下的子项目,是 Spring 组件一站式解决方案,主要是简化了使用 Spring 的难度,简省了繁重的配置,提供了各种启动器,开发者能快速上手。
独立运行、简化配置、自动配置、无代码生成和XML配置、应用监控、上手容易
注解 @EnableAutoConfiguration, @Configuration, @ConditionalOnClass 就是自动配置的核心,首先它得是一个配置文件,其次根据类路径下是否有这个类去自动配置。
启动类上面的注解是@SpringBootApplication,它有三部分组成:
@SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。
@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。
@ComponentScan:Spring组件扫描。
资料
MySQL|Redis|MongoDB对比 资料二
一般指超过指定查询时间的查询称之为慢查询你,导致慢查询的原因有一些几点:
mysql> show variables like "long%";
+-----------------+----------+
| Variable_name | Value |
+-----------------+----------+
| long_query_time | 0.000100 |
+-----------------+----------+
------设置慢查询时间:
mysql> set long_query_time=0.0001;
开启慢查询记录设置:
mysql> show variables like "slow%";
+---------------------+------------------------------------+
| Variable_name | Value |
+---------------------+------------------------------------+
| slow_launch_time | 2 |
| slow_query_log | OFF |
| slow_query_log_file | /opt/mysql/data/localhost-slow.log |
+---------------------+------------------------------------+
---slow_query_log 全局变量设置为“ON”状态
mysql> set global slow_query_log=ON;
sql的优化方向主要有两方面:索引和操作
【索引相关规则】索引相关有如下使用的注意事项:
【操作相关】:
1、垂直(纵向)切分
垂直切分常见有垂直分库和垂直分表两种。
垂直分库就是根据业务耦合性,将关联度低的不同表存储在不同的数据库。做法与大系统拆分为多个小系统类似,按业务分类进行独立划分。与"微服务治理"的做法相似,每个微服务使用单独的一个数据库
垂直分表是基于数据库中的"列"进行,某个表字段较多,可以新建一张扩展表,将不经常用或字段长度较大的字段拆分出去到扩展表中。在字段很多的情况下(例如一个大表有100多个字段),通过"大表拆小表",更便于开发与维护,也能避免跨页问题,MySQL底层是通过数据页存储的,一条记录占用空间过大会导致跨页,造成额外的性能开销。另外数据库以行为单位将数据加载到内存中,这样表中字段长度较短且访问频率较高,内存能加载更多的数据,命中率更高,减少了磁盘IO,从而提升了数据库性能。
2、水平(横向)切分
当一个应用难以再细粒度的垂直切分,或切分后数据量行数巨大,存在单库读写、存储性能瓶颈,这时候就需要进行水平切分了。
水平切分分为库内分表和分库分表,是根据表内数据内在的逻辑关系,将同一个表按不同的条件分散到多个数据库或多个表中,每个表中只包含一部分数据,从而使得单个表的数据量变小,达到分布式的效果
库内分表只解决了单一表数据量过大的问题,但没有将表分布到不同机器的库上,因此对于减轻MySQL数据库的压力来说,帮助不是很大,大家还是竞争同一个物理机的CPU、内存、网络IO,最好通过分库分表来解决。
应用层、表示层、会话层、网络层、传输层、数据链路层、物理层七大部分
TCP提供IP环境下的数据可靠传输,它提供的服务包括数据流传送、可靠性、有效流控、全双工操作和多路复用。通过面向连接、端到端和可靠的数据包发送。通俗说,它是事先为所发送的数据开辟出连接好的通道,然后再进行数据发送;
UDP则不为IP提供可靠性、流控或差错恢复功能。一般来说,TCP对应的是可靠性要求高的应用,而UDP对应的则是可靠性要求低、传输经济的应用。
TCP支持的应用协议主要有:Telnet、FTP、SMTP等;
UDP支持的应用层协议主要有:NFS(网络文件系统)、SNMP(简单网络管理协议)、DNS(主域名称系统)、TFTP(通用文件传输协议)等。
http是一个无状态协议,既是对事务没有状态支持。对应的解决方式有cookie等技术
一、首先HTTP请求服务端生成证书,客户端对证书的有效期、合法性、域名是否与请求的域名一致、证书的公钥(RSA加密)等进行校验;
二、客户端如果校验通过后,就根据证书的公钥的有效, 生成随机数,随机数使用公钥进行加密(RSA加密);
三、消息体产生的后,对它的摘要进行MD5(或者SHA1)算法加密,此时就得到了RSA签名;
四、发送给服务端,此时只有服务端(RSA私钥)能解密。
五、解密得到的随机数,再用AES加密,作为密钥(此时的密钥只有客户端和服务端知道)。
HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。
https比http更加适合用来传递比较敏感的信息,如证件信息,密码等等。
又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
应用设计模式的目的是为了提高代码的可重用性、代码的可读性和代码的可靠性。
1)可以提高程序员的思维能力、编程能力和设计能力。
2)使程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期。
3)使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强。
其他的web容器
Weblogic
JBOSS
Coldfusion
Websphere
GlassFish
BFS:Breadth-First-Search,宽度优先搜索;
DFS:Depth-first search,深度优先搜索。
DFS和BFS主要是运用于对于图和树的搜索,但是绝大部分问题模型都是可以建模变成一个图或者树的,所以差不多不少问题都会涉及到这两个。
方式 | 实现方法 | 基本思想 | 解决问题 | N规模 |
---|---|---|---|---|
DFS | 栈、回溯法 | 一次访问一条路,更接近人的思维方式 | 所有解问题,或连通性问题 | 不能太大,<=200 |
BFS | 队列 | 分治限界法,一次访问多条路,每一层需要存储大量信息 | 最优解问题,如最短路径 可以比较大,因为可以用队列解决, | <=100 |
DFS主要的特性是深度优先,总是不停的往下找,走到没路才罢休。
BFS则是从root开始扩展,每一层都是精密的搜索完整了才下一个。
数据结构比较常见的有,散列(集合)、链表(单向链表、双向链表、循环链表)、线性表(队列,栈)、树、图。
三种数据结构的区别:
有个经典的应用HashMap,HashMap的数据结构用到了数组、链表、红黑树
HashMap数据结构算法分析
存图就是对于每个点u,记录他能到的所有点就行
存储一个图的三种方法:
数据结构
容器就是将软件打包成标准化单元,以用于开发、交付和部署。
容器镜像是轻量的、可执行的独立软件包 ,包含软件运行所需的所有内容:代码、运行时环境、系统工具、系统库和设置。
容器化软件适用于基于Linux和Windows的应用,在任何环境中都能够始终如一地运行。
容器赋予了软件独立性,使其免受外在环境差异(例如,开发和预演环境的差异)的影响,从而有助于减少团队间在相同基础设施上运行不同软件时的冲突。
Docker 是世界领先的软件容器平台。
Docker 使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核 的cgroup,namespace,以及AUFS类的UnionFS等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术。 由于隔离的进程独立于宿主和其它的隔离的进 程,因此也称其为容器。Docke最初实现是基于 LXC.
Docker 能够自动执行重复性任务,例如搭建和配置开发环境,从而解放了开发人员以便他们专注在真正重要的事情上:构建杰出的软件。
用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。
Docker 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 “这段代码在我机器上没问题啊” 这类问题;——一致的运行环境
可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。——更快速的启动时间
避免公用的服务器,资源会容易受到其他用户的影响。——隔离性
善于处理集中爆发的服务器使用压力;——弹性伸缩,快速扩展
可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。——迁移方便
使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。——持续交付和部署
总结,docker提供了一致的运行环境、优良的隔离性、弹性部署、可持续交付与部属
docker部署springboot工程
一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“getUsername()和setTrue()”函数就是一个幂等函数.更复杂的操作幂等保证是利用唯一交易号(流水号)实现。
保证幂等性一般有三点: