JRE是个运行环境,JDK是个开发环境。因此,开发程序时,写的Java程序就是在JDK上,而运行Java程序的时候,就 需要JRE。
在JVM中,内存分为堆内存跟栈内存,对象存储在堆内存中,基本类型存储在栈内存,
用等于的时候,数据为基本类型时,比较的是值,数据为对象时,比较的是地址值,
equals比较的是对象的内容;
hashCode()返回该对象的哈希码值;equals()返回两个对象是否相等,HashCode 用于在散列的存储结构中确定对象的存储地址,如果两个对象equals()相等,那么两个对象的hashCode()方法返回的结果也必然相等,如果两个对象的 hashCode()相同,则 equals()却不一定相等,如果重写equals()方法,必须重写hashCode()方法,以保证equals方法相等时两个对象hashcode返回相同的值
BIO(Blocking I/O)同步阻塞I/O,按顺序执行事情,适用于小型数据
NIO (New I/O) 同步非阻塞I/O,基于事件驱动的思想,解决BIO的大并发问题,有效请求时,才会有对应的一个线程执行,避免了BIO模型下大量线程处于阻塞等待状态的情景,
AIO (Asynchronous I/O) 异步非阻塞I/O,NIO需要使用者线程不停的轮询IO对象,来确定是否有数据准备好可以读了,而AIO则是在数据准备好之后,才会通知数据使用者,不需要不停地轮询了.
Servlet
一种服务器端的Java应用程序
由 Web 容器加载和管理
用于生成动态 Web 内容
负责处理客户端请求
Jsp(全名为Java Server Pages)
是 Servlet 的扩展,本质上还是 Servlet
每个 Jsp 页面就是一个 Servlet 实例
Jsp 页面会被 Web 容器编译成 Servlet,Servlet 再负责响应用户请求
相同点
jsp经编译后就变成了servlet,jsp本质就是servlet,jvm只能识别java的类,不能识别jsp代码,web容器将jsp的代码编译成jvm能够识别的java类。
区别
Servlet 适合动态输出 Web 数据和业务逻辑处理,对于 html 页面内容的修改非常不方便;Jsp 是在 Html 代码中嵌入 Java 代码,适合页面的显示
Servlet中没有内置对象 。
JSP中的内置对象都是必须通过HttpServletRequest对象,HttpServletResponse对象以及HttpServlet对象得到
application 作用域 在所有应用程序中有效
session 在当前会话中有效(从用户打开浏览器开始,到用户关闭浏览器这中间的过程。这个过程可能包含多个请求响应)
request 在当前请求中有效
page 在当前页面有效
1.方便解耦,便于开发(Spring就是一个大工厂,可以将所有对象的创建和依赖关系维护都交给spring管理)
2.spring支持aop编程(spring提供面向切面编程,可以很方便的实现对程序进行权限拦截和运行监控等功能)
3.声明式事务的支持(通过配置就完成对事务的支持,不需要手动编程)
4.方便程序的测试,spring 对junit4支持,可以通过注解方便的测试spring 程序
5.方便集成各种优秀的框架(轻量级框架)
6.降低javaEE API的使用难度(Spring 对javaEE开发中非常难用的一些API 例如JDBC,javaMail,远程调用等,都提供了封装,是这些API应用难度大大降低)
规定了一个接口,这个共有的接口是基于http协议的RESTful接口交互规定的请求了方式,数据格式,以及是表单提交还是异步请求
1、#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号
2、KaTeX parse error: Expected 'EOF', got '#' at position 21: …据直接显示生成在sql中 3.#̲方式能够很大程度防止sql注入…方式无法防止Sql注入, 方 式 一 般 用 于 传 入 数 据 库 对 象 , 例 如 传 入 表 名 和 列 名 , 还 有 排 序 时 使 用 o r d e r b y 动 态 参 数 时 需 要 使 用 方式一般用于传入数据库对象,例如传入表名和列名,还有排序时使用order by动态参数时需要使用 方式一般用于传入数据库对象,例如传入表名和列名,还有排序时使用orderby动态参数时需要使用 ,ORDER BY KaTeX parse error: Expected 'EOF', got '#' at position 21: …mnName} 4.、一般能用#̲的就别用
可以用SHOW ENGINES; 来查询数据库的存储引擎,
MyISAM,MySQL 5.0 之前的默认数据库引擎,最为常用。拥有较高的插入,查询速度,但不支持事务
InnoDB,事务型数据库的首选引擎,支持ACID事务,支持行级锁定, MySQL 5.5 起成为默认数据库引擎
MEMORY是MySQL中一类特殊的存储引擎。它使用存储在内存中的内容来创建表,而且数据全部放在内存中。这些特性与前面的两个很不同。
cookie存储在浏览器端,用于存储用户信息中,一般的网站都会有保持登录也就是说下次你再访问网站的时候就不需要重新登录了,这是因为用户登录的时候我们可以存放了一个 Token 在 Cookie 中,下次登录的时候只需要根据 Token 值来查找用户即可(为了安全考虑,重新登录一般要将 Token 重写);
Session 数据保存在服务器端,Session 的主要作用就是通过服务端记录用户的状态。 典型的场景是购物车,当你要添加商品到购物车的时候,系统不知道是哪个用户操作的,因为 HTTP 协议是无状态的。服务端给特定的用户创建特定的 Session 之后就可以标识这个用户并且跟踪这个用户了.
相对来说 Session 安全性更高。如果使用 Cookie 的一些敏感信息不要写入 Cookie 中,最好能将 Cookie 信息加密然后使用到的时候再去服务器端解密
springioc:将对象的控制权交由spring容器统一管理,降低耦合度,用反射技术实现可以将属性依赖注入进来,不需要主动获取,实现依赖注入大体有下三种方式:通过构造函数注入,通过set方法注入,通过接口方式进行注入
aop:面向切面编程,基于动态代理方式的,分为jdk动态代理和cglib动态代理;
jdk动态代理需要接口,JDK动态代理是基于Java的反射机制实现的,主要涉及java.lang.reflect包中的Proxy和InvocationHandler,InvocationHandler是一个接口,通过实现这个接口定义一个横切的逻辑!然后通过反射机制调用目标类的方法,这样就能动态的把非业务逻辑和业务逻辑动态的拼接在一起,proxy则利用InvocationHandler创建代理实例,来间接的调用代理的方法;
Cglib采用了底层的字节码技术,为代理类创建了一个子类来代理,Cglib因为是用子类代理所以对目标类中的final或者private方法进行代理,Cglib的性能是JDK动态代理的大概十倍,但是Cglib创建动态代理所花费的时间是JDK的大概八倍。因此对于无需频繁创建代理对象的例如单例或者是有实力池的代理,比较适合用Cglib;
主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等,
主要的意图是:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码
切面类:含有切点的类,增强方法,@Aspect注解,里面可配置@Before,对要增强的方法增强;
未提交读:事务的修改,即使没有提交,对其它事务也是可见的;
提交读:一个事务只能读取已经提交的事务所作的修改,换句话说,一个事务所做的修改在提交之前对其它事务是不可见的。
可重复读:同一个事务中多次读取同样数据的结果是一样的.
可串行化:强制事务串行执行
过滤器:
依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符;
拦截器:
依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理;拦截器的配置一般在SpringMVC的配置文件中,使用Interceptors标签;
Filter需要在web.xml中配置,依赖于Servlet;
Interceptor需要在SpringMVC中配置,依赖于框架;
Filter的执行顺序在Interceptor之前
从灵活性上说拦截器功能更强大些,Filter能做的事情,都能做,而且可以在请求前,请求后执行,比较灵活。Filter主要是针对URL地址做一个编码的事情、过滤掉没用的参数、安全校验(比较泛的,比如登录不登录之类),太细的话,还是建议用interceptor。不过还是根据不同情况选择合适的。
1.过滤器:web.xml配置的路径,只能访问登录或者注册页面,通过自定义过滤器类实现过滤器,用户输入用户名和密码(数据库中无需存在该用户名和密码,表示有登录行为)后,创建一个session保存该用户对象,通过servletRequest.getSession(),在过滤器中读取这个session,若是session为null,或者用户名密码错误,通过过滤器过滤,不能通过过滤器,重定向跳转到error.jsp页,成功,跳转成功页面;
2.拦截器: springmvc框架配置文件配置拦截器的路径, 自定义拦截器类实现HandlerInterceptor, 拦截controller跳转的页面;
一、利用数据库同步session
二、利用cookie同步session
三、利用memcache同步session
第一种方法,最影响系统速度的那种,不推荐使用;
第二种方法,效果不错,不过安全隐患一样的存在;
第三种方法,个人觉得第三种方法是最好的,推荐大家使用
https://www.cnblogs.com/zengjin93/p/5569556.html
程序中执行的多个线程,继承Thread类,实现Runnable,实现Callable,java是单继承,多实现,最好用实现接口实现,可以继承其它类,
Runnable没有返回值;Callable可以返回执行结果,是个泛型,和Future、FutureTask配合可以用来获取异步执行的结果
Callable接口的call()方法允许抛出异常;Runnable的run()方法异常只能在内部消化,不能往上继续抛
注:Callalbe接口支持返回执行结果,需要调用FutureTask.get()得到,此方法会阻塞主进程的继续往下执行,如果不调用不会阻塞
线程是在进程中,进程相当于一个程序;
同步:发送一个请求,等待返回,然后再发送下一个请求
异步:发送一个请求,不等待返回,随时可以再发送下一个请求
同步可以避免出现死锁,读脏数据的发生,一般共享某一资源的时候用,如果每个人都有修改权限,同时修改一个文件,有可能使一个人读取另一个人已经删除的内容,就会出错,同步就会按顺序来修改。
比如rabbitmq消息中间件的广播模式,就是一个异步例子。生产者不关心接收者的状态。不需要等待接收者的返回信息
电话,就是一个同步例子。发起者需要等待接收者,接通电话后,通信才开始。需要等待接收者的返回信息
可以直接通过工厂将我需要的对象直接给我,易于功能扩展,例如有个汽车生产工厂,原来有比亚迪产线、大众产线,现在要加一条凯迪拉克产线。只需返回汽车汽车类共有的(父类)凯迪拉克类的对象(此对象是多态对象),而不对其他产线造成影响;
降低客户端和工厂的耦合性
final用于修饰类,方法和变量,修饰的类无法被继承,修饰的变量为常量,修饰的方法为把方法锁定,以防止继承类对其进行更改;
finally:作为异常处理的一部分,它只能用在try/catch语句中,并且附带一个语句块,表示这段语句最终一定会被执行(不管有没有抛出异常),经常被用在需要释放资源的情况下;
finalize:在java.lang.Object里定义的,也就是说每一个对象都有这么个方法。这个方法在gc启动,该对象被回收的时候被调用,其实gc可以回收大部分的对象(凡是new出来的对象,gc都能搞定,一般情况下我们又不会用new以外的方式去创建对象),所以一般是不需要程序员去实现finalize的,特殊情况下,需要程序员实现finalize,当对象被回收的时候释放一些资源,比如:一个socket链接,在对象初始化时创建,整个生命周期内有效,那么就需要实现finalize,关闭这个链接;
使用finalize还需要注意一个事,调用super.finalize();
一个对象的finalize()方法只会被调用一次,而且finalize()被调用不意味着gc会立即回收该对象,所以有可能调用finalize()后,该对象又不需要被回收了,然后到了真正要被回收的时候,因为前面调用过一次,所以不会调用finalize(),产生问题;
Java程序运行时(非编译)所发生的非正常情况或错误;
所有异常的根类为java.lang.Throwable,Throwable下面又派生了两个子类:Error和Exception;
Error表示程序本身无法克服和恢复的一种严重错误,程序只有死的份,如内存溢出和死锁问题等系统问题。
Exception表示还能克服和恢复,其中又分为系统异常和普通异常。系统异常是软件本身缺陷导致的问题,也就是软件开发问题考虑不周所导致的问题,软件使用者无法克服和恢复这种问题,但这种情况下可以选择让软件继续运行或死掉。如数组越界问题(ArrayIndexOutOfBoundsException),空指针异常(NullPointerException),类转换异常(ClassCastException);普通异常是运行环境的变化或异常导致的问题,是用户能够克服的问题,如网路掉线、硬盘空间不足、IO异常发生这种异常后程序不应该死掉;
编译器强制普通异常必须try…catch处理或throws声明继续抛给上层调用方法处理。所以普通异常为checked异常,而系统异常可以处理也可以不处理。编译器不强制用try…catch或throws声明,所以系统异常成为uncheckde异常
1.在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。
2.在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,分配到jvm中的堆中,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,存在jvm的元空间(jdk1.8),与堆内存处于平级在硬盘上,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。
3.无论创建多少个实例对象,永远都只分配了一个static修饰的变量;
普通B/S模式(同步)AJAX技术(异步)
同步:提交请求->等待服务器处理->处理完毕返回 这个期间客户端浏览器不能干任何事
异步: 请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕
Collection是集合类的上级接口,继承与他有关的接口主要有List和Set
Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全等操作
JAVA反射机制是在运行状态中,对于任意一个类。都能都知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称之为java语言的反射机制;反编译 .class --à .java
1、加载类,指定类的完全限定名:包名+类名
Class.forName
2,对象.getClass()
3,类.class
TreeMap是基于比较器Comparator来实现有序的(红黑树),LinkedHashmap是基于链表来实现数据插入有序的;
单例模式,不要在controller中定义成员变量。在Controller中使用ThreadLocal变量;
#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。
KaTeX parse error: Expected 'EOF', got '#' at position 59: …le user; 那么第一条用#̲{}的sql解析为:selec…{}的sql解析为:select id, username, password, role from user where username=;drop table user;
这时候已经sql注入了。
#方式能够很大程度防止sql注入,$方式无法防止Sql注入。
方 式 一 般 用 于 传 入 数 据 库 对 象 , 例 如 传 入 表 名 和 列 名 , 还 有 排 序 时 使 用 o r d e r b y 动 态 参 数 时 需 要 使 用 方式一般用于传入数据库对象,例如传入表名和列名,还有排序时使用order by动态参数时需要使用 方式一般用于传入数据库对象,例如传入表名和列名,还有排序时使用orderby动态参数时需要使用 ,ORDER BY ${columnName}
一般情况下,我们创建的表的类型是InnoDB,如果新增一条记录(不重启mysql的情况下),这条记录的id是8;但是如果重启(文中提到的)MySQL的话,这条记录的ID是6。因为InnoDB表只把自增主键的最大ID记录到内存中,所以重启数据库或者对表OPTIMIZE操作,都会使最大ID丢失。
但是,如果我们使用表的类型是MylSAM,那么这条记录的ID就是8。因为MylSAM表会把自增主键的最大ID记录到数据文件里面,重启MYSQL后,自增主键的最大ID也不会丢失。
注:如果在这7条记录里面删除的是中间的几个记录(比如删除的是3,4两条记录),重启MySQL数据库后,insert一条记录后,ID都是8。因为内存或者数据库文件存储都是自增主键最大ID
打开mysql在命令提示符上输入 select version();
在cmd里面输入 mysql -V
char类型的长度是固定的,varchar的长度是可变的。这就表示,存储字符串’abc’,使用char(10),表示存储的字符将占10个字节(包括7个空字符)使用varchar2(10),,则表示只占3个字节,10是最大值,当存储的字符小于10时,按照实际的长度存储。
char类型的效率比varchar的效率稍高;
varchar2比char节省空间,但是在效率上比char稍差些;
既要获得效率即必须牺牲一点空间,这就是设计上的"以空间换时间"
varchar2虽然比char节省空间,但是一个varchar2列经常被修改,而且每次修改的数据长度不同,这会引起“行迁移的现象”,
而这造成的多余的I/O,是数据库设计中尽量避免的,在这种情况下使用char代替varchar2会更好些。
索引是在存储引擎层实现的,而不是在服务器层实现的,所以不同存储引擎具有不同的索引类型和实现;
B+tree索引
是大多数MySQL存储引擎的默认索引类型,因为不再需要进行全表扫描,只需要对树进行搜索即可,所以查找速度快很多,除了用于查找,还可以用于排序和分组,可以指定多个列作为索引列,多个索引列共同组成键,适用于全键值、键值范围和键前缀查找,其中键前缀查找只适用于最左前缀查找。如果不是按照索引列的顺序进行查
找,则无法使用索引。
InnoDB 的 B+Tree 索引分为主索引和辅助索引。主索引的叶子节点 data 域记录着完整的数据记录,这种索引方式被称为聚簇索引。因为无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。
辅助索引的叶子节点的 data 域记录着主键的值,因此在使用辅助索引进行查找时,需要先查找到主键值,然后再到
主索引中进行查找。
哈希索引
哈希索引能以 O(1) 时间进行查找,但是失去了有序性;
无法用于排序与分组;只支持精确查找,无法用于部分查找和范围查找。
InnoDB 存储引擎有一个特殊的功能叫“自适应哈希索引”,当某个索引值被使用的非常频繁时,会在 B+Tree 索引之上再创建一个哈希索引,这样就让 B+Tree 索引具有哈希索引的一些优点,比如快速的哈希查找。
全文索引
MyISAM 存储引擎支持全文索引,用于查找文本中的关键词,而不是直接比较是否相等。
查找条件使用 MATCH AGAINST,而不是普通的 WHERE。
全文索引使用倒排索引实现,它记录着关键词到其所在文档的映射。
InnoDB 存储引擎在 MySQL 5.6.4 版本中也开始支持全文索引。
空间数据索引
MyISAM 存储引擎支持空间数据索引(R-Tree),可以用于地理数据存储。空间数据索引会从所有维度来索引数据,
可以有效地使用任意维度来进行组合查询。
必须使用 GIS 相关的函数来维护数据。
索引是一种高效获取数据的存储结构,例:hash、 二叉、 红黑。Mysql为什么不用上面三种数据结构而采用B+Tree:若仅仅是 select * from table where id=45 , 上面三种算法可以轻易实现,但若是select * from table where id<6 , 就不好使了,它们的查找方式就类似于"全表扫描",因为他们的高度是不可控的。B+Tree的高度是可控的,mysql通常是3到5层。注意:B+Tree只在最末端叶子节点存数据,叶子节点是以链表的形势互相指向的。
Explain 用来分析 SELECT 查询语句,
select_type : 查询类型,有简单查询、联合查询、子查询等
key : 使用的索引
rows : 扫描的行数
存储过程(Stored Procedure)是一种在数据库中存储复杂程序,以便外部程序调用的一种数据库对象。
存储过程是为了完成特定功能的SQL语句集,经编译创建并保存在数据库中,用户可通过指定存储过程的名字并给定参数(需要时)来调用执行。
存储过程思想上很简单,就是数据库 SQL 语言层面的代码封装与重用。
1.SHOW PROCESSLIST显示哪些线程正在运行
有root权限,您可以看到所有线程。否则,只能看到登录的用户自己的线程,#ID标识,要kill一个语句的时候很有用;
2.使用 explain 命令查询 SQL 语句执行计划
3.开启慢查询日志,查看慢查询的 SQL
重载: 发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以
不同,发生在编译时。
重写: 发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类,
访问修饰符范围大于等于父类;如果父类方法访问修饰符为 private 则子类就不能重写该方法。
JVM内存区域分为五个部分,分别是堆,元空间(方法区jdk1.8前),虚拟机栈,本地方法栈,程序计数器。
堆:存储程序需要的数据,new 创建的对象,有新生代(伊甸园、s0、s1)、老年代,永久代(jdk1.8移除)这几个时期;
虚拟机栈——控制程序执行的流程,Java方法,每一个线程都会开辟内存空间,栈,存的是栈帧(一个方法一个栈帧);描述java方法执行的内存模型;虚拟机栈中执行每个方法的时候,都会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息;
程序计数器
每一个线程都会有一个程序计数器,记录线程指令执行到的位置。
本地方法栈
描述Native方法执行的内存模型
元空间
它用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据,方法区在JDK1.7版本及以前被称为永久代,从JDK1.8永久代被移除;
对象序列化的目标是将对象保存到磁盘中,或允许在网络中直接传输对象。对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,通过网络将这种二进制流传输到另一个网络节点。其他程序一旦获得了这种二进制流,都可以将这种二进制流恢复成原来的Java对象;
序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,
然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。
GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。
GC是垃圾收集器。Java 程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:
System.gc()
Runtime.getRuntime().gc(),但JVM可以屏蔽掉显示的垃圾回收调用。
垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低优先级的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。
在Java诞生初期,垃圾回收是Java最大的亮点之一,因为服务器端的编程需要有效的防止内存泄露问题,然而时过境迁,如今Java的垃圾回收机制已经成为被诟病的东西。移动智能终端用户通常觉得iOS的系统比Android系统有更好的用户体验,其中一个深层次的原因就在于Android系统中垃圾回收的不可预知性。
List:是存储单列数据的集合
Map:存储双列数据的集合
一个程序中可以有多条执行线索同时执行,一个线程就是程序中的一条执行线索,每个线程上都关联有要执行的代码,即可以有多段程序代码同时运行,每个程序至少都有一个线程,即main方法执行的那个线程。如果只是一个cup,它怎么能够同时执行多段程序呢,从宏观上来看,CPU一会执行a线索,一会执行b线索,切换时间很快,给人的感觉a,b在同时执行。
状态:就绪,运行,synchronize阻塞,wait和sleep挂起,结束。wait必须在synchronized内部调用。调用线程的start方法后线程进入就绪状态,线程调度系统(拿到系统时间片)将就绪状态的编程转为运行状态,遇到synchronized语句时,由运行状态转为阻塞,当synchronized获得锁后,由阻塞转为运行,在这种情况下可以调用wait方法转为挂起状态,当线程关联的代码执行完后,线程变为结束状态。
继承Thread类:Thread类本质上是实现了Runnable接口的一个实例,代表一个线程的实例,启动线程的唯一方法就是通过Thread类的start()实例方法;
实现Runnable接口创建线程:如果自己的类已经extends另一个类,就无法直接extends Thread,此时,可以实现一个Runnable接口,为了启动MyThread,需要首先实例化一个Thread,并传入自己的MyThread实例;
事实上,当传入一个Runnable target参数给Thread后,Thread的run()方法就会调用target.run();
实现Callable接口通过FutureTask包装器来创建Thread线程;
使用ExecutorService、Callable、Future实现有返回结果的线程:有了这种特征就不需要再为了得到返回值而大费周折了,可返回值的任务必须实现Callable接口。类似的,无返回值的任务必须实现Runnable接口。
执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了。
注意:get方法是阻塞的,即:线程无返回结果,get方法会一直等待;
反对使用 stop(), 是因为它不安全。 它会解除由线程获取的所有锁定, 而且如果对象处
于一种不连贯状态, 那么其他线程能在那种状态下检查和修改它们。 结果很难检查出真正的问题所在;
suspend()方法容易发生死锁。 调用 suspend()的时候, 目标线程会停
下来, 但却仍然持有在这之前获得的锁定。 此时, 其他任何线程都不能访问锁定的资
源, 除非被"挂起"的线程恢复运行。 对任何线程来说, 如果它们想恢复目标线程, 同
时又试图使用任何一个锁定的资源, 就会造成死锁
1、这两个方法来自不同的类分别是Thread和Object,sleep方法属于Thread类中的静态方法,wait属于Object的成员方法。
2、sleep()是线程类(Thread)的方法,不涉及线程通信,调用时会暂停此线程指定的时间,但监控依然保持,不会释放对象锁,到时间自动恢复;wait()是Object的方法,用于线程间的通信,调用时会放弃对象锁,进入等待队列,待调用notify()/notifyAll()唤醒指定的线程或者所有线程,才进入对象锁定池准备获得对象锁进入运行状态。
3、wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用(使用范围)。
4、sleep()方法必须捕获异常InterruptedException,而wait()\notify()以及notifyAll()不需要捕获异常。
注意:
sleep方法只让出了CPU,而并不会释放同步资源锁。
线程执行sleep()方法后会转入阻塞状态。
sleep()方法指定的时间为线程不会运行的最短时间。因此,sleep()方法不能保证该线程睡眠到期后就开始执行。
notify的作用相当于叫醒睡着的人,而并不会给他分配任务,就是说notify只是让之前调用wait的线程有权利重新参与线程的调度。
回顾我们之前的 SSM 项目,搭建过程还是比较繁琐的,需要:
1)配置 web.xml,加载 spring 和 spring mvc
2)配置数据库连接、配置日志文件
3)配置加载配置文件的读取,开启注解
4)配置mapper文件
独立运行
简化配置
自动配置
无代码生成和XML配置
应用监控
上手容易
简单、快速、方便地搭建项目;对主流开发框架的无配置集成;极大提高了开发、部署效率。
常用注解
@SpringBootApplication:@Configuration、@EnableAutoConfiguration、@ComponentScan。
@Bean,ResponseBody,@RestController
application和bootstarp配置文件,
application文件主要用于Springboot自动化配置文件。
bootstarp文件主要有以下几种用途:
bootstrap 加载优先于 applicaton。bootstrap 主要用于从额外的资源来加载配置信息,还可以在本地外部配置文件中解密属性。这两个上下文共用一个环境,它是任何Spring应用程序的外部属性的来源。bootstrap 里面的属性会优先加载,它们默认也不能被本地相同配置覆盖。
使用Spring Cloud Config注册中心时 需要在bootStarp配置文件中添加链接到配置中心的配置属性来加载外部配置中心的配置信息。
一些固定的不能被覆盖的属性
一些加密/解密的场景
.properties 和 .yml
.yml采取的是缩进的格式 不支持@PeopertySource注解导入配置
spring-boot的启动方式主要有三种:
运行带有main方法类
通过命令行 java -jar 的方式
通过spring-boot-plugin的方式
Spring Cloud 封装了 Netflix 公司开发的 Eureka 模块来实现服务注册和发现;
Eureka 采用了 C-S 的设计架构。Eureka Server 作为服务注册功能的服务器,它是服务注册中心;
Eureka包含两个组件:Eureka Server和Eureka Client;
Eureka Server提供服务注册服务
各个节点启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到
EurekaClient是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除(默认90秒)
Eureka三大角色:
Eureka Server 提供服务注册和发现
Service Provider服务提供方将自身服务注册到Eureka,从而使服务消费方能够找到
Service Consumer服务消费方从Eureka获取注册服务列表,从而能够消费服务
1)首选需要建立eureka服务器,创建spring cloud eureka服务器和创建之前那个配置文件服务器类似,你只需要创建一个空的maven工程,并引入spring boot的相关starter即可,然后创建一个近乎空的执行类,可以看到只需要使用@EnableEurekaServer注解就可以让应用变为Eureka服务器,这是因为spring boot封装了Eureka Server,让你可以嵌入到应用中直接使用,
让服务使用eureka服务器
2)让服务使用eureka服务器,只需添加@EnableDiscoveryClient注解就可以了;
1.用于解决方法之间的依赖,如声明式事务管理,实现原理是动态代理,分为jdk的动态代理和cglib动态代理;
jdk动态代理针对于接口操作,目标类必须实现一个接口,代理类和目标类是兄弟关系;JDK动态代理是基于Java的反射机制实现的,主要涉及到java.lang.reflect包中的Proxy和InvocationHandler;InvocationHandler是一个接口,通过实现这个接口定义一个横切的逻辑!然后通过反射机制调用目标类的方法,这样就能动态的把非业务逻辑和业务逻辑动态的拼接在一起;proxy则利用InvocationHandler创建代理实例,来间接的调用代理的方法;
Cglib既可以代理有接口的类,也可以代理无接口的类。目标类不能用final修饰,代理是目标类的子类;
作用:在程序运行期间,不修改源码对已有方法进行增强。
可以减少重复代码,提高开发效率以及维护方便;
**stackoverflow:**栈内存溢出,开启一个线程,会存入java栈中,以帧为单位,如果这个程序还没有返回,那么这个栈帧一直存在,如果方法的嵌套调用过多,例如递归,java栈中的帧的增多,最终导致这个线程的栈中的所有栈帧的大小的总和大于-Xss设置的值,而产生生StackOverflowError溢出异常;
outofmemory: 堆内存溢出:java堆用于存放对象的实例,当需要为对象的实例分配内存时,而堆的占用已经达到了设置的最大值(通过-Xmx)设置最大值,则抛出OutOfMemoryError异常