Java Summarize

★★★为什么HashMap最大容量是2的30次方?
因为int的最大值是2的31-1,而hashMap最大容量不可以超过int的最大值,所有是2的30次方,
★★★为什么HashMap是2的N次方?HashTable是什么?
2的N次方有一个特点,对一个数取余的时候,可以通过移位运算来进行,HashMap保证性能,所以是2的N次方,
而HashTable则是通过取余,他是任意容量,

★★★ Map我想保证效率,还想保证安全,怎么办?
可以用ConcurrentHashMap来保证效率和安全,ConcurrentHashMap是HashMap的线程安全版本,底层基于lock实现,而HashTable则是基于synchroized的,ConcurrentHashMap是基于段(Segment),段实现了lock,所以这个比hashtable的性能高出很多,

通过分析Hashtable就知道,synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对hash表的不同部分进行的修改。
ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的hash table,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。
有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。
这里“按顺序”是很重要的,否则极有可能出现死锁,在ConcurrentHashMap内部,段数组是final的,并且其成员变量实际上也是final的,但是,仅仅是将数组声明为final的并不保证数组成员也是final的,
这需要实现上的保证。这可以确保不会出现死锁,因为获得锁的顺序是固定的。

set的实现:
HashSet(无序不重复)
LinkedHashSet(按放入顺序有序不重复),继承自HashSet
TreeSet(按红黑树方式有序不重复),实现Comparable接口,保证元素的唯一性,不是hashCode和equals方法

★★★
throwable和Execption是需要强制处理的,要么声明,有么抓取,而error和runtimeExection不需要强制处理,这个就是异常的独特见解,error一般是虚拟机抛出的,而我们可以手动抛出一个error,符合一个java语法的,
当前线程不一定结束,把当前的error的处理掉,下面的程序继续运行

★懒汉式通过加锁,降低效率,可以通过枚举或者内部类.

工厂模式
工作没用过,只是框架用到了, 我还问我的同事,他们也没用过工厂模式.(生成的对象有一个接口,有不同的实现,工厂生产的实现)
★★概念:为调用者提供一个符合要求的对象. 在实例化对象和new 出来的效果是一样的,工厂方法应该用于同种类型的复杂对象的初始化
分为1.静态工厂,2.基于反射的简单工厂,3.多方法工厂(常用)
1和2的缺点就是不同的产品需要不同额外参数的时候 不支持。
3.多方法的工厂模式为不同产品,提供不同的生产方法,使用时 需要哪种产品就调用该种产品的方法,使用方便、容错率高

好处:解耦,后期项目维护方便, 会给系统带来更好的扩展性和更少的修改量
缺点:使项目代码量增加

有一个接口animal,下面有几个实现,比如dog,cat,我们有个方法,这个方法返回的是接口animal,具体的实现是返回animal,的dog
现有一个接口,这个接口下面还有不同的实现,而工厂生产的是实现,
工厂模式必须有一个接口,如果没有则没有意义,我们面向的是一个接口,而不是具体的实现.

单例模式:保证一个类仅有一个实例对象,并提供一个全局的访问点,可以控制资源的使用以及实例产生的数量

通过反射用来做什么:
对象内容拷贝 获取get,set方法 先invoke get方法 拿到值就是属性的值,再作为set方法的参数invoke
怎么对应起来的:
定义两个hashmap,属性名作为key,方法名作为value,
synchronize与lock的区别:
线程少的情况下用synchronize,不是性能高,而是方便,修饰方法与同步代码块,自动释放锁。
线程多的时候,lock比较好,finally里释放锁。
sleep与wait的区别
sleep可以出现在任何地方,是Thread类的静态方法,不会释放对象锁
wait需要写在同步代码块里边,否则爆出无效的监听器异常,会释放对象的锁,
notify唤醒任意一个正在等待的线程。而notifyall唤醒正在wait的线程

高性能:性能高,微信,新浪,很快的刷新出自己想要的内容, 解决方式:数据库缓存(redis和mongodb)
高可用:尽可能的不宕机,尽可能的持续提供服务, 解决方式:集群
高并发:多个请求同时过来,受不了。 解决方式:集群,应用集群和数据库集群。 应用集群:多个Tomcat同时参与,即Nginx负载均衡
数据库集群:主从复制。 写在主,读在从。

redis中的集群包括两方面:数据分区(分布式)和主从复制。 分布式:解决大数据量问题。

与 MC 不同的是,Redis 采用单线程模式处理请求。这样做的原因有 2 个:一个是因为采用了非阻塞的异步事件处理机制;另一个是缓存数据都是内存操作 IO 时间不会太长,单线程可以避免线程上下文切换产生的代价。
Redis 支持持久化,所以 Redis 不仅仅可以用作缓存,也可以用作 NoSQL 数据库。
相比 MC,Redis 还有一个非常大的优势,就是除了 K-V 之外,还支持多种数据格式,例如 list、set、sorted set、hash 等。
Redis 提供主从同步机制,以及 Cluster 集群部署能力,能够提供高可用服务。

redis中怎么解决数据不一致:在应用端是无法解决的(最终一致),在客户端解决,在进行完以后,等待一段时间,让后台同步一下
写在主里边,主给应用应答一下,在通过异步给从同步数据,再给应用一个应答,先应答再同步。 防止数据库扛不住,用消息队列

哪些地方用到redis:
消息队列:用list lpush插到头部 rpoplpush从尾部弹出放在左边第一个,也可以从左边开始取
主从同步的策略: 硬盘(默认)和文件的方式
缓存刷新策略: 设置有效期,expire 缓存中的数据剔除掉:LRU算法(最近最少使用)
redis的备份:快照 save changes 指定文件的路径,默认是当前用户的主目录,文件名是dump
数据缓存: 用string类型的,可以将对象序列化,作为value存进去,也可以将对象转化为json字符串,存json字符串,开发效率高, hash的效率低
redis更新缓存问题: 1.(主动)后台人为点击更新的按钮,从DB中查询最新的数据,存储最新数据到缓存 引发问题:更新缓存数据时,刚删除缓存,正好有用户访问,查不到,影响用户体验度
2.(被动)前台用户查询缓存时候,查不到就去DB查询, 引发问题:在并发请求的时候,就会产生并发的操作
3.(主动)后台点击更新缓存按钮时候,从数据库查询最新数据,不删除缓存,通过遍历数据覆盖和删除无效的数据 引发问题:逻辑相对复杂,而且更新机制不能通用
类似预加载功能,现将数据加到缓存,缓存成功后切换最新的数据,旧数据设置过期
4.(主动,预加载)前台在获取数据的时候需要对应的redis key(简称showing key),通过他查询缓存中的数据,redis内存不足的话,不要用
showing key:可以是最近一次更新缓存的时间戳或者自己的规则

持久化
Redis 提供了 RDB 和 AOF 两种持久化方式,RDB 是把内存中的数据集以快照形式写入磁盘,实际操作是通过 fork 子进程执行,采用二进制压缩存储;AOF 是以文本日志的形式记录 Redis 处理的每一个写入或删除操作。

RDB 把整个 Redis 的数据保存在单一文件中,比较适合用来做灾备,但缺点是快照保存完成之前如果宕机,这段时间的数据将会丢失,另外保存快照时可能导致服务短时间不可用。

AOF 对日志文件的写入操作使用的追加模式,有灵活的同步策略,支持每秒同步、每次修改同步和不同步,缺点就是相同规模的数据集,AOF 要大于 RDB,AOF 在运行效率上往往会慢于 RDB。

缓存穿透
缓存穿透。产生这个问题的原因可能是外部的恶意攻击,例如,对用户信息进行了缓存,但恶意攻击者使用不存在的用户id频繁请求接口,导致查询缓存不命中,然后穿透 DB 查询依然不命中。这时会有大量请求穿透缓存访问到 DB。

解决的办法如下。

对不存在的用户,在缓存中保存一个空对象进行标记,防止相同 ID 再次访问 DB。不过有时这个方法并不能很好解决问题,可能导致缓存中存储大量无用数据。
使用 BloomFilter 过滤器,BloomFilter 的特点是存在性检测,如果 BloomFilter 中不存在,那么数据一定不存在;如果 BloomFilter 中存在,实际数据也有可能会不存在。非常适合解决这类的问题。
缓存击穿
缓存击穿,就是某个热点数据失效时,大量针对这个数据的请求会穿透到数据源。

解决这个问题有如下办法。

可以使用互斥锁更新,保证同一个进程中针对同一个数据不会并发请求到 DB,减小 DB 压力。
使用随机退避方式,失效时随机 sleep 一个很短的时间,再次查询,如果失败再执行更新。
针对多个热点 key 同时失效的问题,可以在缓存时使用固定时间加上一个小的随机数,避免大量热点 key 同一时刻失效。
缓存雪崩
缓存雪崩,产生的原因是缓存挂掉,这时所有的请求都会穿透到 DB。

解决方法:

使用快速失败的熔断策略,减少 DB 瞬间压力;
使用主从模式和集群模式来尽量保证缓存服务的高可用。
实际场景中,这两种方法会结合使用。

session共享:自己写filter,拦截请求,根据sessionID去查session,查不到创建session,存储起来
写一个类实现sessionManager算法,打成jar包,在Tomcat中配置一下
第三种方式:Spring的httpsession,导入httpsession依赖,在web。xml中配置一个filter,将redis集成进来,再导入过来RedisHttpSessionConfiguration

web项目优化:前段静态资源(js,css,html,properties)的优化与应用优化
前端:静态资源压缩, 页面的话,将页面压缩为gz格式,前台请求过来,读进来,放在内存,存在concurrent hashMap里边,key为url,value为这个gz
(就是不用读取硬盘,在内存里边),压缩为gz格式的,文件变小,节约内存,网络传输效率高,浏览器本来也支持

事务:
编程式事务:通过transctionTemplate手动管理事务,实际应用中很少使用
声明式事务:1.开发中经常使用,代码的侵入性小,spring 的声明式事务就是通过AOP实现的(基于TransactionProxyFactoryBean的方式 ),
需要为每个事务管理的类配置一个TransactionProxyFactoryBean进行管理。使用时还需要在类中注入该代理类
2.基于注解方式的声明式事务(在需要使用事务的类上添加注解即可 @Transactional),
3.在我的开发中用的是基于aspectJ的声明式事务,引入AOP和TX的命名空间,配置好之后,按照方法的名字进行管理,无需再类中添加任何东西
平常是以get开头的方法不开启事务,propagation属性的值为NOT-SUPPORT 其余的方法将其的值为SUPPORT,另外rollback-for属性的值为EXCEPTION

dbcp与c3p0还有Tomcat jdbc的比较:
数据库连接池负责的仅仅是建立DataSource,获取(从连接池中获取)Connection,关闭(放回到连接池)Connection)
dbcp 是单线程的,为了保证线程安全会锁整个连接池,性能不佳,太复杂,超过 60 个类,使用静态接口,在 JDK 1.6 编译有问题,发展滞后
Tomcat jdbc:tomcat jdbc pool 近乎兼容 dbcp ,性能更高,异步方式获取连接,是 tomcat 的一个模块,基于 tomcat JULI,使用 Tomcat 的日志框架,
使用 javax.sql.PooledConnection 接口获取连接,支持高并发应用环境,超简单,核心文件只有8个,比 c3p0 还更好的空闲连接处理机制
可在 Tomcat 中直接使用
总结:
总体性能:TomcatJDBC > DBCP > C3P0
网上好多资料都说C3P0的性能要好于DBCP,从我的测试结果来看并不是这样,也许是我的配置有不正确的地方,测试时最大的活动线程配置为100,
并发为150线程时,TomcatJDBC的优势明显,,也就是当并发超过连接池最大的活动线程数,但并没有超过太多的情况下,TomcatJDBC的优势明显,
当并发数为300时,3种连接池性能差距不大,对于一个小型的系统,并发压力不大时,选择哪个连接池都没有太大差别,考虑更多的应该是连接池的稳定性。

        稳定性测试:
               当数据库由于未知原因关闭,重新启动后,连接池是否可以自动重连,无需重启应用服务
               TomcatJDBC和DBCP并没有自动重连机制,这缺陷可以通过修改配置解决,C3P0进行了自动重连
               连接池重连机制:1.同步验证方式   2.心跳验证方式				   

spring security:
在登陆的时候,将密码在前台进行MD5加密,得到一个MD5值,再后台进行将用户名与密码的加密,一般是第一次得到的MD5值加上用户名(所谓的加盐),再进行与数据库的密码对比,数据库的密码就是经过加密的密码,不能手动添加(不能是明文)
在认证完以后,放在session中,存到缓存中,在获取权限与缓存中的权限比较,看是否有权限
在添加用户的时候,执行两次事务,(用户名与密码)还有(用户一些其他的信息),在service层处理,发生异常事务回滚
不能在controller层,否则在有异常的时候,可能会导致信息不完全

线程池:(通过Executors提供四种线程池)
new fixedThreadPool(创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待)
new singleThreadPool(创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行)
new cacheThreadPool(创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程)
newScheduledThreadPool(创建一个定长线程池,支持定时及周期性任务执行。延迟执行)

AOP:就是面向切面编程
横跨多个类的关注点,把软件系统分为核心关注点和横切关注点,作用就是用来将这两个分离开来,
核心关注点经常用来处理业务流程较多,而横切关注点与之关系不大,它的一个特点就是出现在核心关注点的多处,各处基本相似,比如我们的权限日志和事务,切面就是横切关注点的抽象 本身是Java的,只不过是Spring也支持AOP , AOP的底层就是动态代理
日志管理:就是定义一个切面(类上写aspect注解),在切面中有切点(方法上写pointCut注解,包括execution的值为一个方法的权限命名)
在切点的之前和之后可以插入日志等内容
应用:声明式事务和拦截器

动态代理:
为其他对象提供一种代理以控制对这个对象的访问,本质是反射
1.接口的JDK(Spring默认的),
定义一个接口,让一个委托类去实现他,代理类实现invocationHandler,核心方法是invoke,产生的代理对象只能用接口接收
在用代理对象调用方法时候,就会调用invoke方法,返回一个跟接口对应的返回值类型
2.类的Cglib(第三方的),
委托类不能用final修饰,要用来被继承,代理类实现methodInterceptor,核心方法intercept,用到asm jar包,用来转化字节码
生成代理类,产生的代理对象用代理类接收,生成代理对象的时候用到Enhancer增强类,在test中,
传一个委托类的参数,用代理类A再来接受

内存溢出
堆(常见) ,由于太多对象被创建,没有及时回收 导出Excel时候要关流,不然会溢出 解决方案:加大内存,写代码注意点
栈 原因:声明变量太多 递归会导致栈溢出 解决方案:写代码注意点
方法区 原因: static修饰的过多,类加载过多 解决方案:加大内存

前后端分离:
一套后台对应多个前台(一套服务应用于多个客户端)
1:最大的好处就是前端JS可以做很大部分的数据处理工作,对服务器的压力减小到最小
2:后台错误不会直接反映到前台,错误接秒较为友好
3:由于后台是很难去探知前台页面的分布情况,而这又是JS的强项,而JS又是无法独立和服务器进行通讯的。
所以单单用后台去控制整体页面,又或者只靠JS完成效果,都会难度加大,前后台各尽其职可以最大程度的减少开发难度。

java7的特性:

1.1.switch可以接受string类型而不像以前仅仅是int;
2.异常catch可以一次处理完而不像以前一层层的surround;
3.泛型类实例化也不用繁琐的将泛型声明再写一遍;
4.文件读写 会自动关闭流而不像以前那样需要在finally中显式close;
5.数值可以使用下划线分隔;
6.文件读写功能增强,有更简单的api调用;
7.文件改变的事件通知功能;
8.多核 并行计算的支持加强 fork join 框架;
9.还有一些动态特性的加入。

java8的特性:

  1. 1.支持lanmbda表达式,不用再写大量的匿名内部类,代码的可读性会更好、高阶函数引入了函数组合的概念
    2.接口的默认方法,允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法
    3.函数式接口,
    4.方法与构造函数引用
    5.Lambda 作用域
    6.访问局部变量
    7.访问对象字段与静态变量
    8.访问接口的默认方法
    9.Date API
    10.Annotation 注解

java9的特性:

  1. 1.Java 平台级模块系统
    2.Linking
    3.JShell : 交互式 Java REPL
    4.改进的 Javadoc
    5.集合工厂方法
    6.改进的 Stream API
    7.私有接口方法
    8.HTTP/2
    9.多版本兼容 JAR

Bootstrap 的原理就是基于CSS
bootstrap class 加相关属性 table button
官网拿到依赖 导入项目

angularjs 提交后台请求 h t t p 数 据 绑 定 到 http 数据绑定到 httpscope bean.属性 表达式{{属性}} {{name}} ng-bind
官网拿到依赖 导入项目

<script src="js/angular-route.js"></script> 

HTTP协议的特点:

  • 支持客户/服务器模式、简单快速、灵活、无连接、无状态
    http请求由三部分组成,分别是:请求行、消息报头、请求正文 HTTP响应也是由三个部分组成,分别是:状态行、消息报头、响应正文

Struts2与SpringMVC的区别

  • 1、Struts2是类级别的拦截,
    一个类对应一个request上下文,SpringMVC是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上SpringMVC就容易实现restful
    url,而struts2的架构实现起来要费劲,因为Struts2中Action的一个方法可以对应一个url,而其类属性却被所有方法共享,这也就无法用注解或其他方式标识其所属方法了。
    2、由上边原因,SpringMVC的方法之间基本上独立的,独享request
    response数据,请求数据通过参数获取,处理结果通过ModelMap交回给框架,方法之间不共享变量,而Struts2搞的就比较乱,虽然方法之间也是独立的,但其所有Action变量是共享的,这不会影响程序运行,却给我们编码
    读程序时带来麻烦,每次来了请求就创建一个Action,一个Action对象对应一个request上下文。
    3、由于Struts2需要针对每个request进行封装,把request,session等servlet生命周期的变量封装成一个一个Map,供给每个Action使用,并保证线程安全,所以在原则上,是比较耗费内存的。
    4、
    拦截器实现机制上,Struts2有以自己的interceptor机制,SpringMVC用的是独立的AOP方式,这样导致Struts2的配置文件量还是比SpringMVC大。
    5、SpringMVC的入口是servlet,而Struts2是filter(这里要指出,filter和servlet是不同的。以前认为filter是servlet的一种特殊),这就导致了二者的机制不同,这里就牵涉到servlet和filter的区别了。
    6、SpringMVC集成了Ajax,使用非常方便,只需一个注解@ResponseBody就可以实现,然后直接返回响应文本即可,而Struts2拦截器集成了Ajax,在Action中处理时一般必须安装插件或者自己写代码集成进去,使用起来也相对不方便。
    7、SpringMVC验证支持JSR303,处理起来相对更加灵活方便,而Struts2验证比较繁琐,感觉太烦乱。 8、Spring
    MVC和Spring是无缝的。从这个项目的管理和安全上也比Struts2高(当然Struts2也可以通过不同的目录结构和相关配置做到SpringMVC一样的效果,但是需要xml配置的地方不少)。
    9、 设计思想上,Struts2更加符合OOP的编程思想, SpringMVC就比较谨慎,在servlet上扩展。
    10、SpringMVC开发效率和性能高于Struts2。 11、SpringMVC可以认为已经100%零配置。

hibernate:(ORM,数据持久层框架,用来操作数据库的)

  • 1.通过configuration去加载默认配置文件hibernate.cfg.xml
    2.通过配置文件信息创建工厂sessionFactory。(线程安全)
    3.通过sessionFactory得到session;(线程不安全)
    4.通过session去进行数据库操作,并得到transaction接口进行事物控制;

Spring
框架的粘合剂,有两个核心,分别是IOC/DI(控制反转/依赖注入),AOP(面向切面编程/面向方面编程)。主要用来进行bean实例的创建和注入,和事物控制

  • 1.通过web.xml中ContextLoaderListener来融入spring,并加载默认配置文件applicationContext.xml;
    2.action继承ActionSupport,然后通过引入struts-spring-plugin.jar包并且根据配置文件中service的id生成get,set方法来注入service层。
    3…dao层继承于HibernateDaoSupport,并且在dao的配置文件中注入sessionFactory.
    4.通过spring中的配置文件加载hibernate.cfg.xml文件从而融入hibernate.

springMVC:(mvc c层框架)

  • 1.服务器发送请求到DispatcherServlet;
    2.DispatcherServlet调用HandlerMapping解析默认配置文件applicationContex.xml;
    3.调用对应的controller,并执行;
    4.controller执行完毕后,返回字符串或者ModelAndView对象;
    5.如果返回的是字符串,调用ViewResolver将字符串转化为相应的视图,如果返回ModelAndView对象,该对象本身就包含了视图对象信息。
    6.DispatcherServlet将视图对象中的数据输出给服务器,由服务器响应给客户端;

mybits: ORM,数据持久层框架,用来操作数据库

  • 1.根据Resources解析默认配置文件 mabits-config.xml,获取一个输入流;
    2.通过SqlSessionFactoryBuilder读取输入流获取一个SqlSessionFactory;
    3.使用SqlSessionFactory打开SqlSession;
    4.通过sqlSession操作数据库,并控制事物;

日常工作中的总结:

  • 1:controller 中requestBody接受参数 前端不要用form表单 用payload 不用requestBody时候正常提交
  • 2:列表页面返回时候 两条sql 一个查询count 一个查询分页
  • 3: 数据推送 在本机调试调用data push withdraw接口 同时启动data loading 观察dataloading 日志,数据库记录
  • 4:添加menu菜单时候,menu表以及access_permission表还有role_permission表
  • 5: 返回年月日时分秒的时候sql用DATE_FORMAT(cc.collection_time,’%Y-%m-%d %T’) AS’collection_time’这个函数,数据库类型用String
  • 6: CC service报404,测试环境没有问题,重新部署api gate way也不行,是由于Nginx没有配转发
  • 7: load balancer 404 找不到对应的服务,是否注册同一个Eureka,client服务名字是否写对,配置文件配置服务名称,重启服务
    8: 单一查询,部署后各个服务别的接口没有问题,单独他超时,测试没有问题,sql是跨库的,由于生产数据量大,加索引
    9:控制台打印出来Date如果为时间戳,要转化为时分秒的话,删掉最后三位
    10:大数据量列表查询,考虑数据库表结构,优化sql,尤其是在列表查询下做子查询时候
    11: docker服务器看日志,kubectl get pods -o wide 查询该服务器有多少节点 ssh IP 然后sudo docker ps -a |grep debt 得到ID sudo docker logs -f (ID)08d9fb033b9e
    12:报表系统大数据量查询时候,首先看执行计划,如果有可能走的索引但是没有走索引,用force index(索引名字)加在表名后边
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值