java面试题目

1.项目中Spring AOP用在什么地方,为何这么用,切点,织入,通知,用本身的话描述一下,AOP原理,动态代理2种实现。html

主要是事务那方面,采用声明式的事务配置方式,是AOP给你封装好的。java

通知:node

定义:切面也须要完成工做。在 AOP 术语中,切面的工做被称为通知。mysql

工做内容:通知定义了切面是什么以及什么时候使用。除了描述切面要完成的工做,通知还解决什么时候执行这个工做。linux

Spring 切面可应用的 5 种通知类型:web

Before——在方法调用以前调用通知redis

After——在方法完成以后调用通知,不管方法执行成功与否算法

After-returning——在方法执行成功以后调用通知spring

After-throwing——在方法抛出异常后进行通知sql

Around——通知包裹了被通知的方法,在被通知的方法调用以前和调用以后执行自定义的行为

链接点:

定义:链接点是一个应用执行过程当中可以插入一个切面的点。 链接点能够是调用方法时、抛出异常时、甚至修改字段时、 切面代码能够利用这些点插入到应用的正规流程中 程序执行过程当中可以应用通知的全部点。

切点:

定义:若是通知定义了“什么”和“什么时候”。那么切点就定义了“何处”。切点会匹配通知所要织入的一个或者多个链接点。 一般使用明确的类或者方法来指定这些切点。

做用:定义通知被应用的位置(在哪些链接点)

切面:

定义:切面是通知和切点的集合,通知和切点共同定义了切面的所有功能——它是什么,在什么时候何处完成其功能。

引入: 引入容许咱们向现有的类中添加方法或属性

织入: 织入是将切面应用到目标对象来建立的代理对象过程。 切面在指定的链接点被织入到目标对象中,在目标对象的生命周期中有多个点能够织入。

AOP原理:面向切面编程,就是把可重用的功能提取出来,而后将这些通用功能在合适的时候织入到应用程序中,好比事务管理、权限控制、日志记录、性能统计等。

动态代理的实现:

CGLIB中的动态代理是JDK proxy的一个很好的补充,在JDK中实现代理时,要求代理类必须是继承接口的类,由于JDK最后生成的proxy class其实就是实现了被代理类所继承的接口而且继承了java中的Proxy类,经过反射找到接口的方法,调用InvocationHandler的invoke 方法实现拦截。CGLIb中最后生成的proxy class是一个继承被代理类的class,经过重写被代理类中的非final的方法实现代理。

总结为: JDK proxy:代理类必须实现接口,不须要引来第三方库

CGLIB: 代理类不能是final,代理的方法也不能是final(继承限制),针对类实现的代理,必须依赖CGLib类库。(hibernate中相关的代理采用的是CGLib来执行)。

2.Spring里面注解用过没有?autowired 和resource区别

@Resource和@Autowired都是作bean的注入时使用,其实@Resource并非Spring的注解,它的包是javax.annotation.Resource,须要导入,可是Spring支持该注解的注入。

一、共同点

二者均可以写在字段和setter方法上。二者若是都写在字段上,那么就不须要再写setter方法。

二、不一样点

(1)@Autowired

@Autowired为Spring提供的注解,须要导入包org.springframework.beans.factory.annotation.Autowired;只按照byType注入。

@Autowired注解是按照类型(byType)装配依赖对象,默认状况下它要求依赖对象必须存在,若是容许null值,能够设置它的required属性为false。若是咱们想使用按照名称(byName)来装配,能够结合@Qualifier注解一块儿使用。以下:

(2)@Resource

@Resource默认按照ByName自动注入,由J2EE提供,须要导入包javax.annotation.Resource。@Resource有两个重要的属性:name和type,而Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。

因此,若是使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。若是既不制定name也不制定type属性,这时将经过反射机制使用byName自动注入策略。

注:最好是将@Resource放在setter方法上,由于这样更符合面向对象的思想,经过set、get去操做属性,而不是直接去操做属性。

3.Linux命令,怎么日志文件里面找关键字

一、查看日志 前 n行

  cat 文件名 | head -n 数量

  demo:

    cat  test.log | head -n 200  # 查看test.log前200行

二、查看日志 尾 n行

  cat 文件名 | tail -n 数量

  demo:

    cat  test.log | tail -n 200  # 查看test.log倒数200行

三、根据 关键词 查看日志 并返回关键词所在行

  方法一:cat 路径/文件名 | grep 关键词

  demo:

    cat  test.log | grep "http"  # 返回test.log中包含http的全部行

  方法二:grep -i 关键词 路径/文件名  (与方法一效果相同,不一样写法而已)

  demo:

    grep -i "http" ./test.log  # 返回test.log中包含http的全部行

单个文件可使用vi或vim编辑器打开日志文件,使用编辑器里的查找功能。在查看模式下,符号/后面跟关键字向下查找,符号?后面跟关键字向上查找,按n查找下一个,按N查找上一个。

4.怎么杀死一个进程

方法1: 经过kill 进程id的方式能够实现, 首先须要知道进程id, 例如,想要杀死firefox的进程,经过 ps -ef|grep firefox,能够查到firefox的进程id: 而后经过 kill 3781 就能够关闭进程了. 补充: 1. kill -9 来强制终止退出, 例如: kill -9 3781  kill -9 -1 终止你拥有的所有进程。

方法2: killall 经过程序的名字,来杀死进程 例如: killall firefox 注意: 该命令可使用 -9 参数来强制杀死进程, killall -9 firefox

方法3: pkill 经过程序的名字, 直接杀死全部进程 例如: pkill firefox

 

5.MQ,zookeeper,dubbo,redis,是否了解分布式,是否了解负载均衡?

MQ 消息队列(上游--消息队列--下游) 在高并发环境下,因为来不及同步处理,请求每每会发生阻塞,好比大量的insert、update之类的请求同时到达mysql,直接致使无数的行锁和表锁,从而触发too many connections错误,经过消息队列,能够异步处理请求,从而缓解系统压力。

MQ的不足是: 1)系统更复杂,多了一个MQ组件 2)消息传递路径更长,延时会增长 3)消息可靠性和重复性互为矛盾,消息不丢不重难以同时保证 4)上游没法知道下游的执行结果,这一点是很致命的。 调用方实时依赖执行结果的业务场景,请使用调用,而不是MQ。

何时使用MQ

【典型场景一:数据驱动的任务依赖】  

什么是任务依赖,举个栗子,互联网公司常常在凌晨进行一些数据统计任务,这些任务之间有必定的依赖关系,好比:

1)task3须要使用task2的输出做为输入

2)task2须要使用task1的输出做为输入 这样的话,tast1, task2, task3之间就有任务依赖关系,必须task1先执行,再task2执行,载task3执行。 

采用MQ解耦: 1)task1准时开始,结束后发一个“task1 done”的消息 2)task2订阅“task1 done”的消息,收到消息后第一时间启动执行,结束后发一个“task2 done”的消息 3)task3同理  

采用MQ的优势是:

1)不须要预留buffer,上游任务执行完,下游任务总会在第一时间被执行

2)依赖多个任务,被多个任务依赖都很好处理,只须要订阅相关消息便可

3)有任务执行时间变化,下游任务都不须要调整执行时间  

须要特别说明的是,MQ只用来传递上游任务执行完成的消息,并不用于传递真正的输入输出数据。

【典型场景二:上游不关心执行结果】

上游须要关注执行结果时要用“调用”,上游不关注执行结果时,就可使用MQ了。  

举个栗子,58同城的不少下游须要关注“用户发布帖子”这个事件,好比招聘用户发布帖子后,招聘业务要奖励58豆,房产用户发布帖子后,房产业务要送2个置顶,二手用户发布帖子后,二手业务要修改用户统计数据。

若是使用调用关系,会致使上下游逻辑+物理依赖严重

优化方案是,采用MQ解耦: 1)帖子发布成功后,向MQ发一个消息 2)哪一个下游关注“帖子发布成功”的消息,主动去MQ订阅

其优势是:1.上游执行时间短,2.上下游逻辑+物理解耦,,模块之间不相互依赖.3.新增一个下游消息关注方,上游不须要修改任何代码

典型场景三:上游关注执行结果,但执行时间很长  有时候上游须要关注执行结果,但执行结果时间很长(典型的是调用离线处理,或者跨公网调用),也常用回调网关+MQ来解耦。  

举个栗子,微信支付,跨公网调用微信的接口,执行时间会比较长,但调用方又很是关注执行结果,此时通常怎么玩呢? 

通常采用“回调网关+MQ”方案来解耦:

1)调用方直接跨公网调用微信接口

2)微信返回调用成功,此时并不表明返回成功

3)微信执行完成后,回调统一网关

4)网关将返回结果通知MQ

5)请求方收到结果通知 

总结

MQ是一个互联网架构中常见的解耦利器。

何时不使用MQ? 上游实时关注执行结果  

何时使用MQ? 1)数据驱动的任务依赖

2)上游不关心多下游执行结果

3)异步返回执行时间长 

 

zookeeper

1.ZooKeeper是什么?
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,它是集群的管理者,监视着集群中各个节点的状态,根据节点提交的反馈进行下一步合理操做。最终,将简单易用的接口和性能高效、功能稳定的系统提供给用户

2.ZooKeeper提供了什么?

1)文件系统

2)通知机制

3.Zookeeper文件系统

每一个子目录项如 NameService 都被称做为znode,和文件系统同样,咱们可以自由的增长、删除znode,在一个znode下增长、删除子znode,惟一的不一样在于znode是能够存储数据的。 

有四种类型的znode: 

一、PERSISTENT-持久化目录节点 

客户端与zookeeper断开链接后,该节点依旧存在 

二、PERSISTENT_SEQUENTIAL-持久化顺序编号目录节点 

客户端与zookeeper断开链接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号 

三、EPHEMERAL-临时目录节点 

客户端与zookeeper断开链接后,该节点被删除 

四、EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点 

客户端与zookeeper断开链接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号

 

 

4.Zookeeper通知机制

客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、被删除、子目录节点增长删除)时,zookeeper会通知客户端。

5.Zookeeper作了什么?

1.命名服务   2.配置管理   3.集群管理   4.分布式锁  5.队列管理

6.Zookeeper命名服务

在zookeeper的文件系统里建立一个目录,即有惟一的path。在咱们使用tborg没法肯定上游程序的部署机器时便可与下游程序约定好path,经过path即能互相探索发现。

7.Zookeeper的配置管理

程序老是须要配置的,若是程序分散部署在多台机器上,要逐个改变配置就变得困难。如今把这些配置所有放到zookeeper上去,保存在 Zookeeper 的某个目录节点中,而后全部相关应用程序对这个目录节点进行监听,一旦配置信息发生变化,每一个应用程序就会收到 Zookeeper 的通知,而后从 Zookeeper 获取新的配置信息应用到系统中就好

8.Zookeeper集群管理

所谓集群管理无在意两点:是否有机器退出和加入、选举master。 

对于第一点,全部机器约定在父目录GroupMembers下建立临时目录节点,而后监听父目录节点的子节点变化消息。一旦有机器挂掉,该机器与 zookeeper的链接断开,其所建立的临时目录节点被删除,全部其余机器都收到通知:某个兄弟目录被删除,因而,全部人都知道:它上船了。

新机器加入也是相似,全部机器收到通知:新兄弟目录加入,highcount又有了,对于第二点,咱们稍微改变一下,全部机器建立临时顺序编号目录节点,每次选取编号最小的机器做为master就好。

9.Zookeeper分布式锁

有了zookeeper的一致性文件系统,锁的问题变得容易。锁服务能够分为两类,一个是保持独占,另外一个是控制时序。 

对于第一类,咱们将zookeeper上的一个znode看做是一把锁,经过createznode的方式来实现。全部客户端都去建立 /distribute_lock 节点,最终成功建立的那个客户端也即拥有了这把锁。用完删除掉本身建立的distribute_lock 节点就释放出锁。 

对于第二类, /distribute_lock 已经预先存在,全部客户端在它下面建立临时顺序编号目录节点,和选master同样,编号最小的得到锁,用完删除,依次方便。

10.Zookeeper队列管理

两种类型的队列:

一、同步队列,当一个队列的成员都聚齐时,这个队列才可用,不然一直等待全部成员到达。 

二、队列按照 FIFO 方式进行入队和出队操做。 

第一类,在约定目录下建立临时目录节点,监听节点数目是不是咱们要求的数目。 

第二类,和分布式锁服务中的控制时序场景基本原理一致,入列有编号,出列按编号。

11.Zookeeper设计目的

1.最终一致性:client不论链接到哪一个Server,展现给它都是同一个视图,这是zookeeper最重要的性能。 

2.可靠性:具备简单、健壮、良好的性能,若是消息被到一台服务器接受,那么它将被全部的服务器接受。 

3.实时性:Zookeeper保证客户端将在一个时间间隔范围内得到服务器的更新信息,或者服务器失效的信息。但因为网络延时等缘由,Zookeeper不能保证两个客户端能同时获得刚更新的数据,若是须要最新数据,应该在读数据以前调用sync()接口。 

4.等待无关(wait-free):慢的或者失效的client不得干预快速的client的请求,使得每一个client都能有效的等待。 

5.原子性:更新只能成功或者失败,没有中间状态。 

6.顺序性:包括全局有序和偏序两种:全局有序是指若是在一台服务器上消息a在消息b前发布,则在全部Server上消息a都将在消息b前被发布;偏序是指若是一个消息b在消息a后被同一个发送者发布,a必将排在b前面。 

 

12.Zookeeper工做原理

Zookeeper 的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫作Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和 leader的状态同步之后,恢复模式就结束了。状态同步保证了leader和Server具备相同的系统状态。 

为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。全部的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。

13.Zookeeper 下 Server工做状态

每一个Server在工做过程当中有三种状态: 

LOOKING:当前Server不知道leader是谁,正在搜寻
LEADING:当前Server即为选举出来的leader
FOLLOWING:leader已经选举出来,当前Server与之同步

14.Zookeeper选主流程(basic paxos)

当leader崩溃或者leader失去大多数的follower,这时候zk进入恢复模式,恢复模式须要从新选举出一个新的leader,让全部的Server都恢复到一个正确的状态。Zk的选举算法有两种:一种是基于basic paxos实现的,另一种是基于fast paxos算法实现的。系统默认的选举算法为fast paxos。

1.选举线程由当前Server发起选举的线程担任,其主要功能是对投票结果进行统计,并选出推荐的Server; 

2.选举线程首先向全部Server发起一次询问(包括本身); 

3.选举线程收到回复后,验证是不是本身发起的询问(验证zxid是否一致),而后获取对方的id(myid),并存储到当前询问对象列表中,最后获取对方提议的leader相关信息(id,zxid),并将这些信息存储到当次选举的投票记录表中; 

4.收到全部Server回复之后,就计算出zxid最大的那个Server,并将这个Server相关信息设置成下一次要投票的Server; 

5.线程将当前zxid最大的Server设置为当前Server要推荐的Leader,若是此时获胜的Server得到n/2 + 1的Server票数,设置当前推荐的leader为获胜的Server,将根据获胜的Server相关信息设置本身的状态,不然,继续这个过程,直到leader被选举出来。 经过流程分析咱们能够得出:要使Leader得到多数Server的支持,则Server总数必须是奇数2n+1,且存活的Server的数目不得少于n+1. 每一个Server启动后都会重复以上流程。在恢复模式下,若是是刚从崩溃状态恢复的或者刚启动的server还会从磁盘快照中恢复数据和会话信息,zk会记录事务日志并按期进行快照,方便在恢复时进行状态恢复。

redis

Redis是一款开源的、高性能的键-值存储(key-value store)。它常被称做是一款数据结构服务器(data structure server)。

Redis的键是String类型,值能够包括字符串(strings)类型,同时它还包括哈希(hashes)、列表(lists)、集合(sets)和 有序集合(sorted sets)等数据类型。 对于这些数据类型,你能够执行原子操做。

为了得到优异的性能,Redis采用了内存中(in-memory)数据集(dataset)的方式。同时,Redis支持数据的持久化,须要常常将内存中的数据同步到磁盘来保证持久化。

Redis一样支持主从复制(master-slave replication),而且具备很是快速的非阻塞首次同步( non-blocking first synchronization)、网络断开自动重连等功能。同时Redis还具备其它一些特性,其中包括简单的事物支持、发布订阅 ( pub/sub)、管道(pipeline)和虚拟内存(vm)等 。

Redis功能:

持久化:

redis是一个支持持久化的内存数据库,即redis须要常常将内存中的数据同步到磁盘来保证持久化,这是相对memcache来讲的一个大的优点。redis支持两种持久化方式,一种是 Snapshotting(快照)也是默认方式,另外一种是Append-only file(缩写aof)的方式。 

主从复制:

主从复制容许多个slave server拥有和master server相同的数据库副本。下面是关于redis主从复制的一些特色
1.master能够有多个slave。
2.除了多个slave连到相同的master外,slave也能够链接其余slave造成图状结构。
3.主从复制不会阻塞master。也就是说当一个或多个slave与master进行初次同步数据时,master能够继续处理client发来的请求。相反slave在初次同步数据时则会阻塞,不能处理client的请求。
4.主从复制能够用来提升系统的可伸缩性(咱们能够用多个slave 专门用于client的读请求,好比sort操做可使用slave来处理),也能够用来作简单的数据冗余。
5.能够在master禁用数据持久化,只须要注释掉master 配置文件中的全部save配置,而后只在slave上配置数据持久化。

事务:

redis对事务的支持目前还比较简单。redis只能保证一个client发起的事务中的命令能够连续的执行,而中间不会插入其余client的命令。 
Multi 事物开始
Exec 执行事务
Discard 放弃事物
Watch 监听key
Unwatch 放弃全部key的监听
watch 命令会监视给定的key,当exec时候若是监视的key从调用watch后发生过变化,则整个事务会失败。注意watch的key是对整个链接有效的,和事务同样,若是链接断开,监视和事务都会被自动清除。

发布订阅:

发布订阅(pub/sub)是一种消息通讯模式。订阅者能够经过subscribe和psubscribe命令向redis server订阅本身感兴趣的消息类型,redis将消息类型称为通道(channel)。当发布者经过publish命令向redis server发送特定类型的消息时。订阅该消息类型的所有client都会收到此消息。这里消息的传递是多对多的。一个client能够订阅多个 channel,也能够向多个channel发送消息。
Subscribe
Unsubscribe
Psubscribe
Punsubscribe
Publish

管道:

redis是一个cs模式的tcp server,使用和http相似的请求响应协议。一个client能够经过一个socket链接发起多个请求命令。每一个请求命令发出后client一般 会阻塞并等待redis服务处理,redis处理完后请求命令后会将结果经过响应报文返回给client。

虚拟内存:

redis没有使用os提供的虚拟内存机制而是本身实现了本身的虚拟内存机制 ,可是思路和目的都是相同的。就是暂时把不常常访问的数据从内存交换到磁盘中,从而腾出内存空间用于其余须要访问的数据。

Redis应用场景:

1.取最新N个数据的操做
好比典型的取你网站的最新文章,经过下面方式,咱们能够将最新的5000条评论的ID放在Redis的List集合中,并将超出集合部分从数据库获取
使用LPUSH latest.comments<ID>命令,向list集合中插入数据 
插入完成后再用LTRIM latest.comments 0 5000命令使其永远只保存最近5000个ID 
而后咱们在客户端获取某一页评论时能够用下面的逻辑(伪代码) 
FUNCTION get_latest_comments(start,num_items):
id_list = redis.lrange("latest.comments",start,start+num_items-1)
IF id_list.length < num_items 
id_list = SQL_DB("SELECT ... ORDER BY time LIMIT ...") 
END 
RETURN id_list 
END 
若是你还有不一样的筛选维度,好比某个分类的最新N条,那么你能够再建一个按此分类的List,只存ID的话,Redis是很是高效的。

 2.排行榜应用,取TOP N操做

这个需求与上面需求的不一样之处在于,前面操做以时间为权重,这个是以某个条件为权重,好比按顶的次数排序,这时候就须要咱们的sorted set出马了,将你要排序的值设置成sorted set的score,将具体的数据设置成相应的value,每次只须要执行一条ZADD命令便可。
3.须要精准设定过时时间的应用
好比你能够把上面说到的sorted set的score值设置成过时时间的时间戳,那么就能够简单地经过过时时间排序,定时清除过时数据了,不只是清除Redis中的过时数据,你彻底能够把Redis里这个过时时间当成是对数据库中数据的索引,用Redis来找出哪些数据须要过时删除,而后再精准地从数据库中删除相应的记录。
4.计数器应用
Redis的命令都是原子性的,你能够轻松地利用INCR,DECR命令来构建计数器系统。

5.Uniq操做,获取某段时间全部数据排重值
这个使用Redis的set数据结构最合适了,只须要不断地将数据往set中扔就好了,set意为集合,因此会自动排重。
6.实时系统,反垃圾系统
经过上面说到的set功能,你能够知道一个终端用户是否进行了某个操做,能够找到其操做的集合并进行分析统计对比等。没有作不到,只有想不到。
7.Pub/Sub构建实时消息系统
Redis的Pub/Sub系统能够构建实时的消息系统,好比不少用Pub/Sub构建的实时聊天系统的例子。
8.构建队列系统
使用list能够构建队列系统,使用sorted set甚至能够构建有优先级的队列系统。
9.缓存
这个没必要说了,性能优于Memcached(在某些方面,并非全面优于),数据结构更多样化。

 

Redis总结:

Redis使用最佳方式是所有数据in-memory。 
Redis更多场景是做为Memcached的替代者来使用。 
当须要除key/value以外的更多数据类型支持时,使用Redis更合适。 
当存储的数据不能被剔除时,使用Redis更合适。(持久化)

对数据高并发读写
对海量数据的高效率存储和访问 
对数据的高可扩展性和高可用性(分布式)

redis和memcached的区别:

1 Redis不只仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储。
2 Redis支持数据的备份,即master-slave模式的数据备份。
3 Redis支持数据的持久化,能够将内存中的数据保持在磁盘中,重启的时候能够再次加载进行使用。

4 memcache挂掉后,数据不可恢复; redis数据丢失后能够经过aof恢复

在Redis中,并非全部的数据都一直存储在内存中的。这是和Memcached相比一个最大的区别(我我的是这么认为的)。

负载均衡

当一台服务器的性能达到极限时,咱们可使用服务器集群来提升网站的总体性能。那么,在服务器集群中,须要有一台服务器充当调度者的角色,用户的全部请求都会首先由它接收,调度者再根据每台服务器的负载状况将请求分配给某一台后端服务器去处理。 那么在这个过程当中,调度者如何合理分配任务,保证全部后端服务器都将性能充分发挥,从而保持服务器集群的总体性能最优,这就是负载均衡问题。

负载均衡算法

一、轮询法

  将请求按顺序轮流地分配到后端服务器上,它均衡地对待后端的每一台服务器,而不关心服务器实际的链接数和当前的系统负载。

二、随机法

     经过系统的随机算法,根据后端服务器的列表大小值来随机选取其中的一台服务器进行访问。由几率统计理论能够得知,随着客户端调用服务端的次数增多,

其实际效果愈来愈接近于平均分配调用量到后端的每一台服务器,也就是轮询的结果。

三、源地址哈希法

     源地址哈希的思想是根据获取客户端的IP地址,经过哈希函数计算获得的一个数值,用该数值对服务器列表的大小进行取模运算,获得的结果即是客服端要访问服务器的序号。采用源地址哈希法进行负载均衡,同一IP地址的客户端,当后端服务器列表不变时,它每次都会映射到同一台后端服务器进行访问。

四、加权轮询法

  不一样的后端服务器可能机器的配置和当前系统的负载并不相同,所以它们的抗压能力也不相同。给配置高、负载低的机器配置更高的权重,让其处理更多的请;而配置低、负载高的机器,给其分配较低的权重,下降其系统负载,加权轮询能很好地处理这一问题,并将请求顺序且按照权重分配到后端。

五、加权随机法

     与加权轮询法同样,加权随机法也根据后端机器的配置,系统的负载分配不一样的权重。不一样的是,它是按照权重随机请求后端服务器,而非顺序。

六、最小链接数法

     最小链接数算法比较灵活和智能,因为后端服务器的配置不尽相同,对于请求的处理有快有慢,它是根据后端服务器当前的链接状况,动态地选取其中当前积压链接数最少的一台服务器来处理当前的请求,尽量地提升后端服务的利用效率,将负责合理地分流到每一台服务器。

id全局自增如何实现?

treemap

如何设计一个循环队列?

构造方法 :设置队列长度

Front()从队首获取元素

Rear()从队尾获取元素

enQueue()向循环队列插入一个元素

deQueue()向循环队列删除一个元素

isEmpty()检查循环队列是否为空

isFull()检查循环队列是否已满

jdbc链接数据库的流程:

JDBC流程:
第一步:加载Driver类,注册数据库驱动;
第二步:经过DriverManager,使用url,用户名和密码创建链接(Connection);
第三步:经过Connection,使用sql语句打开Statement对象;
第四步:执行语句,将结果返回resultSet;
第五步:对结果resultSet进行处理;
第六步:倒叙释放资源resultSet-》preparedStatement-》connection。

抽象类和接口的使用场景:

抽象类:

1. 你想要在几个关联紧密的类之间共享代码。

2. 你想要继承抽象类的那些类有一些公共方法或属性抑或是有修改protected或private属性的权限。这时你也能够考虑使用抽象类。

3. 你想要声明非静态或者是非最终执行的属性。你能够得到而且修改这些属性所属的对象的状态。

接口:

1. 用相互之间无关的类实现你的接口。举例来讲,可比较的和可克隆的那些接口可使用无关的类来实现。

2. 你想指定一个特定数据类型的行为,可是不用去关心由谁来实现这一行为。

3. 你想要利用多继承的优点。

spring boot和spring的区别

想了解区别,其实就是Spring Boot提供了哪些特征:

1.Spring Boot能够创建独立的Spring应用程序;

2.内嵌了如Tomcat,Jetty和Undertow这样的容器,也就是说能够直接跑起来,用不着再作部署工做了。

3.无需再像Spring那样搞一堆繁琐的xml文件的配置;

4.能够自动配置Spring;

5.提供了一些现有的功能,如量度工具,表单数据验证以及一些外部配置这样的一些第三方功能;

6.提供的POM能够简化Maven的配置;

spring boot和spring cloud的区别

一、Spring boot 是 Spring 的一套快速配置脚手架,能够基于spring boot 快速开发单个微服务;Spring Cloud是一个基于Spring Boot实现的云应用开发工具;

二、Spring boot专一于快速、方便集成的单个个体,Spring Cloud是关注全局的服务治理框架;

三、spring boot使用了默认大于配置的理念,不少集成方案已经帮你选择好了,能不配置就不配置,Spring Cloud很大的一部分是基于Spring boot来实现。

四、Spring boot能够离开Spring Cloud独立使用开发项目,可是Spring Cloud离不开Spring boot,属于依赖的关系。 

springcloud包含服务注册、发现、熔断等功能 。

为何须要springcloud?一个服务编写好后,一启动就会自动注册到服务中心,调用方只管向服务中心发送服务的名称和参数,根本不关注服务的路径。springboot就是作服务的工具,springcloud是管理服务运行的工具。 

spring mvc和三层架构的区别

MVC是一种设计模式,其实现有Struts、SPringMVC等,三层架构主要有数据访问层、业务层、展示层,其展示层能够用MVC模式,数据访问层能够用Hibernate,该层所作事务直接操做数据库、业务层就是写本身业务的地方了,是针对数据层的操做。

Spring的出现,下降了三层架构的耦合,达到解耦的目的(固然Spring的做用还有不少),因此,如今就流行SSH、S2SH之类的。

归并排序思想和代码

两路归并排序算法思路:

分而治之(divide - conquer);每一个递归过程涉及三个步骤
第一, 分解: 把待排序的 n 个元素的序列分解成两个子序列, 每一个子序列包括 n/2 个元素.
第二, 治理: 对每一个子序列分别调用归并排序MergeSort, 进行递归操做
第三, 合并: 合并两个排好序的子序列,生成排序结果.

代码实现

public  static  int [] sort( int [] a, int  low, int  high){
         int  mid = (low+high)/ 2 ;
         if (low<high){
             sort(a,low,mid);
             sort(a,mid+ 1 ,high);
             //左右归并
             merge(a,low,mid,high);
         }
         return  a;
     }
     
     public  static  void  merge( int [] a,  int  low,  int  mid,  int  high) {
         int [] temp =  new  int [high-low+ 1 ];
         int  i= low;
         int  j = mid+ 1 ;
         int  k= 0 ;
         // 把较小的数先移到新数组中
         while (i<=mid && j<=high){
             if (a[i]<a[j]){
                 temp[k++] = a[i++];
             } else {
                 temp[k++] = a[j++];
             }
         }
         // 把左边剩余的数移入数组 
         while (i<=mid){
             temp[k++] = a[i++];
         }
         // 把右边边剩余的数移入数组
         while (j<=high){
             temp[k++] = a[j++];
         }
         // 把新数组中的数覆盖nums数组
         for ( int  x= 0 ;x<temp.length;x++){
             a[x+low] = temp[x];
         }
     }
java寻找数组中第k大的数
优先级队列默认状况下是最小堆

aqs 独占锁 共享锁 公平锁 非公平锁

简介

AQS实现锁机制并非经过synchronized——给对象加锁实现的,事实上它仅仅是一个工具类!它没有使用更高级的机器指令,也不靠关键字,更不依靠JDK编译时的特殊处理,仅仅做为一个普普统统的类就完成了代码块的访问控制。

AQS使用标记位+队列的方式(FIFO队列),记录获取锁、竞争锁、释放锁等一些类锁操做。但更准确的说,AQS并不关心什么是锁,对于AQS来讲它只是实现了一系列的用于判断资源是否能够访问的API,而且封装了在访问资源受限时,将请求访问的线程加入队列、挂起、唤醒等操做。AQS关心的问题以下:

1.资源不可访问时,怎么处理?

2.资源时能够被同时访问,仍是在同一时间只能被一个线程访问?

3.若是有线程等不及资源了,怎么从AQS队列中退出?

至于资源可否被访问的问题,则交给子类去实现。

站在使用者的角度,AQS的功能主要分为两类:独占锁和共享锁。在它的全部子类中,要么实现了它的独占功能的API,要么实现了共享功能的API,但不会同时使用两套API,即便是ReentrantReadWriteLock,也是经过两个内部类:读锁和写锁,分别使用两套API来实现的。

当AQS的子类实现独占功能时,如ReentrantLock,资源是否能够被访问被定义为:只要AQS的state变量不为0,而且持有锁的线程不是当前线程,那么表明资源不可访问。

当AQS的子类实现共享功能时,如CountDownLatch,资源是否能够被访问被定义为:只要AQS的state变量不为0,那么表明资源不能够为访问。 

ReentrantLock会保证在同一时间有且只有一个线程获取到锁,其他线程所有挂起,直到该拥有锁的线程释放锁,被挂起的线程被唤醒从新开始竞争锁。

ReentrantLock的加锁所有委托给内部代理类完成,ReentrantLock只是封装了统一的一套API而已,而ReentrantLock又分为公平锁和非公平锁。 

公平锁:每一个线程抢占锁的顺序为前后调用lock方法的顺序,并依此顺序得到锁,相似于排队吃饭;

非公平锁:每一个线程抢占锁的顺序不变,谁运气好,谁就得到锁,和调用lock方法的前后顺序无关,相似后插入。

非公平锁的lock方法的处理方式:在lock的时候先直接CAS修改一次state变量(尝试获取锁),成功就返回,不成功再排队,从而达到不排队直接抢占的目的。

而对于公平锁:则是老老实实的开始就走AQS的流程排队获取锁。若是前面有人调用过其lock方法,则排在队列中前面,也就更有机会更早的获取锁,从而达到“公平”的目的。

共享锁与独占锁的对比

与AQS的独占功能同样,共享锁是否能够被获取的判断为空方法,交由子类去实现。

与AQS的独占功能不一样,当锁被头节点获取后,独占功能是只有头节点获取锁,其他节点的线程继续沉睡,等待锁被释放后,才会唤醒下一个节点的线程,而共享功能是只要头节点获取锁成功,就在唤醒自身节点对应的线程的同时,继续唤醒AQS队列中的下一个节点的线程,每一个节点在唤醒自身的同时还会唤醒下一个节点对应的线程,以实现共享状态的“向后传播”,从而实现共享功能。

synchronized可重入怎么实现

可重入:

若一个程序或子程序能够“在任意时刻被中断而后操做系统调度执行另一段代码,这段代码又调用了该子程序不会出错”,则称其为可重入(reentrant或re-entrant)的。

即当该子程序正在运行时,执行线程能够再次进入并执行它,仍然得到符合设计时预期的结果。与多线程并发执行的线程安全不一样,可重入强调对单个线程执行时从新进入同一个子程序仍然是安全的。

咱们回来看synchronized,synchronized拥有强制原子性的内部锁机制,是一个可重入锁。所以,在一个线程使用synchronized方法时调用该对象另外一个synchronized方法,即一个线程获得一个对象锁后再次请求该对象锁,是永远能够拿到锁的

在Java内部,同一个线程调用本身类中其余synchronized方法/块时不会阻碍该线程的执行,同一个线程对同一个对象锁是可重入的,同一个线程能够获取同一把锁屡次,也就是能够屡次重入。缘由是Java中线程得到对象锁的操做是以线程为单位的,而不是以调用为单位的。

synchronized可重入锁的实现

以前谈到过,每一个锁关联一个线程持有者和一个计数器。当计数器为0时表示该锁没有被任何线程持有,那么任何线程都均可能得到该锁而调用相应方法。当一个线程请求成功后,JVM会记下持有锁的线程,并将计数器计为1。此时其余线程请求该锁,则必须等待。而该持有锁的线程若是再次请求这个锁,就能够再次拿到这个锁,同时计数器会递增。当线程退出一个synchronized方法/块时,计数器会递减,若是计数器为0则释放该锁。

手写一个线程安全的生产者和消费者

import java.util.*;


public class consumer {

/**
* @param args
*/

//消费者
private List<Integer> queue;
public consumer(List<Integer> queue){
this.queue=queue;
}
public void run(){
try{
while(true){
if(Thread.currentThread().isInterrupted()) break;

synchronized(queue){
if(queue.size()==0){
queue.wait();
queue.notifyAll();
}
int data=queue.remove(0);
}
Thread.sleep(1000);
}
}catch(InterruptedException e){
e.printStackTrace();
}
}

public static void main(String[] args) {
// TODO Auto-generated method stub

}

}

//生产者
class Producer implements Runnable {
private List<Integer> queue;
private int length;

public Producer(List<Integer> queue, int length) {
this.queue = queue;
this.length = length;
}

@Override
public void run() {
try {
while (true) {

if (Thread.currentThread().isInterrupted())
break;
Random r = new Random();
long data = r.nextInt(100);
synchronized (queue) {
if (queue.size() >= length) {
queue.notifyAll();
queue.wait();
} else
queue.add(data);
}
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}

}

}

java中的io

字节输入流:InputStream 

字节输出流:OutputStream

字符输入流:Reader

字符输出流:Writer

linux如何查找某个目标字符串在文件的哪一行

grep -n "xxx" file   其中xxx为要查找的字符串,file为文件名

tcp与udp的应用场景

注重通讯的实时性与可靠性应该选用tcp 如文件传输、重要状态的更新,邮件、浏览器等

注重通讯数据的完整性以及速度时应该选用udp 如视频传输、实时通讯等。

spring中bean的生命周期:

apache和tomcat的区别

1.apache是web服务器,tomcat是应用(java)服务器,它只是一个servlet(jsp也翻译成servlet)容器,能够认为是apache的扩展。

2..apache和tomcat均可以作为独立的web服务器来运行。可是apache不能解释java程序(jsp,serverlet)

3.Apache是普通服务器,自己只支持html即普通网页。不过能够经过插件支持PHP,还能够与Tomcat连通(单向Apache链接Tomcat,就是说经过Apache能够访问Tomcat资源。反之否则)

4.二者都是一种容器,只不过发布的东西不一样。apache是html容器,功能像IIS同样,tomcat是jsp/servlet容器,用于发布JSP及JAVA的,相似的有IBM的webshere、EBA的Weblogic,sun的JRun等

5.apache和tomcat是独立的,在同一台服务器上能够集成。 

数据库查询变慢了怎么办?

1.根据查询条件,创建索引;
2.优化查询程序;
3.提升网速;
4.扩大服务器的内存;
5.若可能增长服务器CPU个数;

6.分库分表
数据切分就是将数据分散存储到多个数据库中,使得单一数据库中的数据量变小,经过扩充主机的数量缓解单一数据库的性能问题,从而达到提高数据库操做性能的目的。

object类的结构

内存泄露的例子

内存泄漏:申请内存后,没法释放已申请的空间,无用对象持续占有内存得不到及时释放。

1.静态集合类:静态集合类生命周期和应用程序同样长。

2.监听器:在释放的时候没有删除监听器

3.物理链接:数据库链接和网络链接,除非显式关闭,不然不会自动被gc回收

4.内部类

5.单例模式:单例对象持有一个外部对象的引用,那么这个外部对象就不会被回收。

group by子句使用注意事项

当查询中存在group by子句时,select列表(或是having子句)中只能存在分组函数,或是出如今group by子句中的字段。 分组函数:max,min,sum,avg,count。

滑动窗口和拥塞控制

相关文章
相关标签/搜索