测试识别二维码

hello world

进程的优点

编程相对容易;通常不需要考虑锁和同步资源的问题。

更强的容错性:比起多线程的一个好处是一个进程崩溃了不会影响其他进程。

有内核保证的隔离:数据和错误隔离。

综述任务工作类型分两种,一个是IO密集型,一个是CPU密集型

tomcat内部采用的就是多线程,上百个客户端访问同一个web应用,tomcat接入后都是把后续的处理扔给一个新的线程来处理,这个新的线程最后调用到我们的servlet程序,比如doGet或者doPost方法

如果只有一个CPU的话,底层是按照分时复用的原则,各个线程按照时间片来获得CPU资源。

为什么有人说自己在Javaweb开发的是后几乎没有用过多线程?

因为有多线程的地方 servlet 容器或者其他开发框架都已经实现掉了!

拷贝文件使用多线程,那是没有用的!以多线程来提高效率的场景一般在 CPU 计算型,而不是在 IO 读写型。

CPU 可以会有多个核心并行处理计算,但是磁盘 IO 就没这功能了,磁头只有一个,根本不可能靠多线程提高效率!

.后台任务:如定时向大量(100W以上)的用户发送邮件;定期更新配置文件、任务调度(如quartz),一些监控用于定期信息采集都会用到多线程

多线程的好处

创建速度快(相对进程而言),方便高效的数据共享

共享数据:多线程间可以共享同一虚拟地址空间;多进程间的数据共享就需要用到共享内存、信号量等IPC技术,比较复杂;

资源利用率更好

缺点

对线程进行管理要求额外的 CPU开销。线程的使用会给系统带来上下文切换的额外负担。当这种负担超过一定程度时,多线程的特点主要表现在其缺点上,比如用独立的线程来更新数组内每个元素。

线程的死锁。即较长时间的等待或资源竞争以及死锁等多线程症状。(可以设想王世伟)

进程线程间创建的开销不足作为选择的依据,因为一般我们都是使用线程池或者进程池,在系统启动时就创建了固定的线程或进程,不会频繁的创建和销毁

这一句话说的好,毕竟数据源用的就是线程池。

线程活跃性问题

1.死锁:哲学家问题,就是多个线程相互占用着其他资源不释放。

2.活锁:行人礼让,不断重复执行相同的操作一直失败。

3.饥饿锁:优先级太低,一直执行不到

4.丢失信号:公交站坐过站,线程等待一个已经发生过的事件。

CPU执行权

6月20日,跟小帅,栋哥,王鑫,卢俊芬视频,怎么说呢,总感觉听爽,说说上班的事吧。

王世伟这一周的任务,说白了就是今天才解决完,遇到两个坑给卡主了,我帮他解决了,

我只是在反省,倘若没我,貌似有些自大,当然估计也只是在这有这个资本吧。他这问题何时才能OK

兴许这就是人与人之间的差距吧,他这么说的,不管通过什么方式,总是搞出来了,这也是人家的能力吧。

比较佩服。。。

map指定初始化大小 元素个数/负载因子+1

遍历推荐使用entryset,这只需要遍历一次,如果是keyset则需要遍历两次

jdk1.8可以使用foreach

//npe我去,就是nullpointerexception问题,对于返回值为int,当其包装类为null是会报npe,自动解箱

oracle当查询为空时是没有默认值的。

若问遇到的问题,可以说那个跨域通用的方法。也可以说说oracle转sqlserver,分区表导入

assert断言,单元测试不允许使用syso,应该使用assert,也是java的关键字

单元测试遵循bcde原则(反正我也不知道是个什么玩意)

禁止字符串拼接访问数据库(很有道理,避免sql注入)

数据库为什么都用小写字母,因为虽然window不区分,但是linux是区分的。

ORacle索引,explain诊断

sql优化的目标,至少达到range级别,要求是ref级别,最好是consts

consts表单中最多一个匹配行(主键或者唯一索引)

ref表单中的普通索引

range对索引进行范围检索

建立组合索引得看区分度,比如where a=? and b=? 只需要a加索引即可

where a>? and b=? 也必须把b放到前面

不使用外检,存储过程,真是失望啊(飞航云+貌似两个都是用了,怪不得效率。。。)

in能避免则比避免,避免不了尽量控制在1000以内

一律不使用*

类布尔成员变量不要加is,对应的数据库字段需要加is_

对于mybatis参数应该使用#{},#param#,不要使用${},不能防止sql注入

Hessian是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能。 相比WebService,Hessian更简单、快捷。采用的是二进制RPC协议,因为采用的是二进制协议,所以它很适合于发送二进制数据。

hessian是一个采用二进制格式传输的服务框架

传输协议比较出名的有http、tcp、udp等等,http、tcp、udp都是在基于Socket概念上为某类应用场景而扩展出的传输协议

即使是单核cpu也支持多线程执行代码,cpu通过给每个线程分配cpu时间片来实现这个机制。时间片是cpu分配给各个线程的时间,因为时间片非常短,所以cpu通过不停切换线程执行,让我们感觉多个线程是同时执行的,时间片一般为几十毫秒。

session和cookie问题

自己先总结一点吧,session服务器对象,cookie是浏览器对象,说这跟废话一样

cookie是浏览器使用cookie存储一些浏览浏览器上的信息

session是记录在服务器上,session就是一个回话,就是访问一个浏览器由打开到关闭的过程,第一次访问,服务器默认会给浏览器返回一个jsessionid=asdfasdf,之后再次访问的时候就一直会携带这个jsessionid。

session通过setMaxInactiveInterval这个方法来设置回话失效时间,单位为s秒

浏览器访问服务器之后响应体中会有一个set-cookie头用于cookie值设置

终于实现了多个浏览器共享session,或者说是浏览器关闭之后再次打开session里面的值还是有的。

可以在初次访问的时候,将对应的jsessionid放入cookie中设置下过期时间,放入硬盘存储.

一个web站点可以给一个web浏览器发送多个cookie,一个浏览器也可以存储多个web站点提供的cookie。

最多存储300个cookie,每个站点最多20个,cookie不超过4k

http转发和重定向的区别

转发只能转发到同一web应用中的组件,重定向可以到同一站点的不同程序中的资源,也可以使用绝对url访问其他站点资源

转发就是浏览器访问一个web资源,之后web资源访问另一个web资源,url地址不变。重定向就是浏览器访问web资源后通知浏览器再去访问另一个web资源,url地址会发生变化

转发可以在调用者与被调用者之间共享相同的request对象和Response对象,重定向则不可以

forward跟include就是这么的简单,include是包含,也就是之前的servlet处理的内容拿过来罢了。

自定义标签

自己写一个java类,需要继承jsp包下面的一个标签类,

写一个tag配置文件,之后在里面写一个访问的url,里面用来进行对应java类的配置

jQuery也是有自己的校验规则插件。

servlet执行过程

客户端浏览器发起一个请求,web服务器将请求转发给servlet容器,servlet容器解析请求的url根据web.xml匹配给对应的servlet,之后并将request和response对象传递给对应的servlet,request携带请求的信息,servlet处理完业务逻辑之后将信息通过response对象返回。。。到位

springMVC执行过程

1.客户端向浏览器发送请求被springMVC的前端控制器dispatcherservlet拦截。

2.之后dispatcherservlet根据请求的URL(统一资源定位符)进行解析,得到URI(请求资源标识符),然后根据这uri调用handerMapping获得该handler配置的所有相关对象,包括handler对象以及handler对应的拦截器,这些对象都会被封装到一个handlerexecutionchain对象中返回。

3.dispatcherservlet根据得到的handler对象选择一个合适的handleradapter。从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器。

4.handleradapter会根据适配的结果调用真正的处理器,完成功能处理并返回一个modelandview对象。(逻辑视图对象)

5.只是一个逻辑视图对象,需要经过视图解析器viewresolver将其解析为具体的view。

6.view会根据传进来的model模型数据进行渲染,此时的model实际是一个map数据结构,因此可以支持更多视图技术

7.控制权交给dispatcherservlet,由它返回响应给用户。

数据库优化

避免null值

关联查询代替子查询

避免使用外检

Tomcat服务器优化(内存,并发连接数,缓存)

a) 内存优化:主要是对Tomcat启动参数进行优化,我们可以在Tomcat启动脚本中修改它的最大内存数等等。

b)线程数优化:Tomcat的并发连接参数,主要在Tomcat配置文件中server.xml中配置,比如修改最小空闲连接线程数,用于提高系统处理性能等等。

c) 优化缓存:打开压缩功能,修改参数,比如压缩的输出内容大小默认为2KB,可以适当的修改。

Struts工作流程0

a) 客户端发出一个请求到servlet容器

b) 请求经过一些列过滤被filterdispatcher调用,filterdispatch通过actionMapper去找相对应的action。

c) Actionmapper找到对应的action返回给filterdispatch,dispatch把处理权交给actionproxy

d) Actionproxy通过配置文件找到对应的action类

e) Actionproxy创建一个actionIinvocation的实例处理业务逻辑

f) 一旦action处理完毕,actioninvocation负责根据stuts.xml的配置找到对应的返回结果。返回结果通常是jsp页面。

synchronized和Lock的区别

主要相同点:Lock能完成synchronized所实现的所有功能

主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。Lock的锁定是通过代码实现的,而synchronized是在JVM层面上实现的,synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。Lock还有更强大的功能,例如,它的tryLock方法可以非阻塞方式去拿锁。Lock锁的范围有局限性,块范围,而synchronized可以锁住块、对象、类。

本地方法

Synchronized和ReentrantLock

设计模式

1.装饰者模式说io基类(定义为接口),具体被装饰对象,装饰者抽象类,具体装饰者

说:由装被饰对象,被装饰对象的基类,装饰者抽象类,具体装饰者组成

动态地给一个对象添加一些额外的职责。就增加功能来说, Decorator模式相比生成子类更为灵活。该模式以对客 户端透明的方式扩展对象的功能。

1.Component(被装饰对象的基类)

定义一个对象接口,可以给这些对象动态地添加职责。

2.ConcreteComponent(具体被装饰对象)

定义一个对象,可以给这个对象添加一些职责。

3.Decorator(装饰者抽象类)

维持一个指向Component实例的引用,并定义一个与Component接口一致的接口。

4.ConcreteDecorator(具体装饰者)

具体的装饰对象,给内部持有的具体被装饰对象,增加具体的职责。

2.适配器模式说io

说: 适配器模式有三种实现方式,①类适配器模式②对象适配器模式③接口适配器模式。适配器有三个角色,目标角色 ,源对象,适配器角色

类适配器与对象适配器的使用场景一致,仅仅是实现手段稍有区别,接口适配器模式就是当接口有太多方法的时候,可以用抽象类来实现接口,方法体简单置空。

适配器模式有三个重要角色:

目标角色(Target),要转换成的目标接口。在我的代码例子中,是中国的两孔接口

源角色(Adaptee),需要被转换的源接口。在我的代码例子中,是美国的三孔接口

适配器角色(Adapter),核心是实现Target接口, 组合Adaptee接口

3.单例模式说在线人数

懒汉式,线程不安全,只适合单线程模式,因为它是在判断对象为null才开始创建,创建对象是有时间的,及时很短,可以说到==跟equals

懒汉式(加锁),线程安全,获取实例的方法上加了synchronized关键字,天生线程安全,因为是一开始就创建了。缺点:每一次获取实例的时候都有一个试图去获取锁的过程。是很耗费时间的

双重检验,加同步代码块,先判断为空的话获取锁对象,获取到之后再次判断为null来创建对象。优点:为空了才会获取锁。会出现问题,好像是由于jvm设计的原因。对,是指令重排序,倘若加了volatile

恶汉式,啥也不说,上去先创建一个。既支持多线程,效率也高 缺点:没有lazy loading的效果,从而降低内存的使用率

静态内部类持有,优点:达到了lazy load的效果,也实现了多线程的效果(虽然不懂后面的)

4.责任链模式说过滤器

5.代理模式

6.工厂模式

7.策略模式、

jvm

如上图所示,首先Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.class后缀),然后由JVM中的类加载器加载各个类的字节码文件,加载完毕之后,交由JVM执行引擎执行。在整个程序执行过程中,JVM会用一段空间来存储程序执行期间需要用到的数据和相关信息,这段空间一般被称作为Runtime Data Area(运行时数据区),也就是我们常说的JVM内存。因此,在Java中我们常常说到的内存管理就是针对这段空间进行管理(如何分配和回收内存空间)。

jvm运行时数据区是由①程序计数器②java方法栈③本地方法栈④方法去⑤堆 五部分组成

程序计数器:是一块较小的区域,可以看做是当前线程所执行的字节码行号指示器,存储的是下一条需要执行的字节码指令,分支,循环,跳转异常处理等信息。各个线程之间的数据是私有的,是独立执行的。如果执行的是java方法,计数器存储的就是虚拟机字节码指令地址,如果是native方法,存储的就是undefined。

java方法栈:跟程序计数器一样,是线程私有的,生命周期跟线程相同,描述的就是java方法执行的内存模型,每个方法被执行的时候都会创建一个栈帧,用于存储局部变量表,操作数栈,方法出口等信息。每一个方法由调用直至执行完毕的过程就是一次栈帧在虚拟机栈由入到出的过程。还存储了对对象的引用,貌似还有什么逃逸分析,可以在栈上分配对象。这个区域会存在两种异常:1.若果线程请求的栈深度大于虚拟机所允许的深度,则则会抛出stackOverflowerror异常。如果虚拟机栈可以动态扩展,当无法申请到足够的内存的时候就会抛出outofmemoryerror异常。 搜嘎,原来是虚拟机栈申请不到足够内存才会抛出outofmemoryerror

本地方法栈:

局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、

float、long、double)、对象引用(reference 类型,它不等同于对象本身,根据不同的虚拟

机实现,它可能是一个指向对象起始地址的引用指针,也可能指向一个代表对象的句柄或

者其他与此对象相关的位置)和returnAddress 类型(指向了一条字节码指令的地址)。

其中64 位长度的long 和double 类型的数据会占用2 个局部变量空间(Slot),其余

的数据类型只占用1 个。局部变量表所需的内存空间在编译期间完成分配,当进入一个

方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间

不会改变局部变量表的大小。

jmm

java Java中通过多线程机制使得多个任务同时执行处理,所有的线程共享JVM内存区域main memory,而每个线程又单独的有自己的工作内存,当线程与内存区域进行交互时,数据从主存拷贝到工作内存,进而交由线程处理(操作码+操作数

  • 发表于:
  • 原文链接:https://kuaibao.qq.com/s/20181010G1QURA00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券