1、数据库左连接右连接
1.内联接(典型的联接运算,使用像 = 或 <> 之类的比较运算符)。包括相等联接和自然联接。
内联接使用比较运算符根据每个表共有的列的值匹配两个表中的行。例如,检索 students和courses表中学生标识号相同的所有行。 2.外联接。外联接可以是左向外联接、右向外联接或完整外部联接。 在 FROM子句中指定外联接时,可以由下列几组关键字中的一组指定:1)LEFT JOIN或LEFT OUTER JOIN
左向外联接的结果集包括LEFT OUTER子句中指定的左表的所有行,而不仅仅是联接列所匹配的行。如果左表的某行在右表中没有匹配行,则在相关联的结果集行中右表的所有选择列表列均为空值。2)RIGHT JOIN 或 RIGHT OUTER JOIN
右向外联接是左向外联接的反向联接。将返回右表的所有行。如果右表的某行在左表中没有匹配行,则将为左表返回空值。 3)FULL JOIN 或 FULL OUTER JOIN 完整外部联接返回左表和右表中的所有行。当某行在另一个表中没有匹配行时,则另一个表的选择列表列包含空值。如果表之间有匹配行,则整个结果集行包含基表的数据值。 3、交叉联接 交叉联接返回左表中的所有行,左表中的每一行与右表中的所有行组合。交叉联接也称作笛卡尔积。
2、IOC AOP
IOC就是典型的工厂模式,通过sessionfactory去注入实例。
AOP就是典型的代理模式的体现。
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
spring的IoC容器是spring的核心,spring AOP是spring框架的重要组成部分。
在传统的程序设计中,当调用者需要被调用者的协助时,通常由调用者来创建被调用者的实例。但在spring里创建被调用者的工作不再由调用者来完成,因此控制反转(IoC);创建被调用者实例的工作通常由spring容器来完成,然后注入调用者,因此也被称为依赖注入(DI),依赖注入和控制反转是同一个概念。
面向方面编程(AOP)是以另一个角度来考虑程序结构,通过分析程序结构的关注点来完善面向对象编程(OOP)。OOP将应用程序分解成各个层次的对象,而AOP将程序分解成多个切面。spring AOP 只实现了方法级别的连接点,在J2EE应用中,AOP拦截到方法级别的操作就已经足够。在spring中,未来使IoC方便地使用健壮、灵活的企业服务,需要利用spring AOP实现为IoC和企业服务之间建立联系。
IOC:控制反转也叫依赖注入。利用了工厂模式 将对象交给容器管理,你只需要在spring配置文件总配置相应的bean,以及设置相关的属性,让spring容器来生成类的实例对象以及管理对象。在spring容器启动的时候,spring会把你在配置文件中配置的bean都初始化好,然后在你需要调用的时候,就把它已经初始化好的那些bean分配给你需要调用这些bean的类(假设这个类名是A),分配的方法就是调用A的setter方法来注入,而不需要你在A里面new这些bean了。AOP:面向切面编程。(Aspect-Oriented Programming)
AOP可以说是对OOP的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。 将程序中的交叉业务逻辑(比如安全,日志,事务等),封装成一个切面,然后注入到目标对象(具体业务逻辑)中去。实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码.
3、线程实现方式
一、继承Thread类创建线程类
(1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。
(2)创建Thread子类的实例,即创建了线程对象。
(3)调用线程对象的start()方法来启动该线程。
二、通过Runnable接口创建线程类
(1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
(2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
(3)调用线程对象的start()方法来启动该线程。
三、通过Callable和Future创建线程
(1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
(2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
(3)使用FutureTask对象作为Thread对象的target创建并启动新线程。
(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
二、创建线程的三种方式的对比
采用实现Runnable、Callable接口的方式创见多线程时,优势是:
线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。
在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
劣势是:
编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。
使用继承Thread类的方式创建多线程时优势是:
编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。
劣势是:
线程类已经继承了Thread类,所以不能再继承其他父类。
4、Spring
Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式) 开源框架。
spring 的优点有:
1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦 2.可以使用容易提供的众多服务,如事务管理,消息服务等 3.容器提供单例模式支持 4.容器提供了AOP技术,利用它很容易实现如权限拦截,运行期监控等功能 5.容器提供了众多的辅助类,能加快应用的开发 6.spring对于主流的应用框架提供了集成支持,如hibernate,JPA,Struts等 7.spring属于低侵入式设计,代码的污染极低 8.独立于各种应用服务器 9.spring的DI机制降低了业务对象替换的复杂性 10.Spring的高度开放性,并不强制应用完全依赖于Spring,开发者可以自由选择spring的部分或全部
5、ActivityMQ引用场景
①.异步处理:用户注册后,需要发注册邮件和注册短信。传统的做法有两种 1.串行的方式;2.并行方式(一般是先发短信再发邮件,但是这里可以同时发)
②.应用解耦:在下单(下单和库存)时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其他的后续操作了。实现订单系统与库存系统的应用解耦
③.流量削锋:秒杀活动,一般会因为流量过大,导致流量暴增,应用挂掉。为解决这个问题,一般需要在应用前端加入消息队列。a、可以控制活动的人数。b、可以缓解短时间内高流量压垮应用
④.日志处理:日志处理是指将消息队列用在日志处理中,日志采集客户端,负责日志数据采集,定时写受写入Kafka队列
⑤.JMS消息服务:JMS(JAVA Message Service,java消息服务)API是一个消息服务的标准/规范,允许应用程序组件基于JavaEE平台创建、发送、接收和读取消息。它使分布式通信耦合度更低,消息服务更加可靠以及异步性。
6、数据库事物
事务(Transaction)是并发控制的基本单位。所谓的事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。
事务具有以下4个基本特征。
Atomic(原子性):事务中包含的操作被看做一个逻辑单元,这个逻辑单元中的操作要么全部成功,要么全部失败。
● Consistency(一致性):只有合法的数据可以被写入数据库,否则事务应该将其回滚到最初状态。
● Isolation(隔离性):事务允许多个用户对同一个数据进行并发访问,而不破坏数据的正确性和完整性。同时,并行事务的修改必须与其他并行事务的修改相互独立。
● Durability(持久性):事务结束后,事务处理的结果必须能够得到固化。
2.事务的语句 开始事物:BEGIN TRANSACTION
提交事物:COMMIT TRANSACTION 回滚事务:ROLLBACK TRANSACTION3.事务的4个属性 ①原子性(Atomicity):事务中的所有元素作为一个整体提交或回滚,事务的个元素是不可分的,事务是一个完整操作。 ②一致性(Consistemcy):事物完成时,数据必须是一致的,也就是说,和事物开始之前,数据存储中的数据处于一致状态。保证数据的无损。 ③隔离性(Isolation):对数据进行修改的多个事务是彼此隔离的。这表明事务必须是独立的,不应该以任何方式以来于或影响其他事务。 ④持久性(Durability):事务完成之后,它对于系统的影响是永久的,该修改即使出现系统故障也将一直保留,真实的修改了数据库7、Solo配置
8、序列化方式
1、Java原生序列化
Java原生序列化方法即通过Java原生流(InputStream和OutputStream之间的转化)的方式进行转化。需要注意的是JavaBean实体类必须实现Serializable接口,否则无法序列化。
2、Json序列化
Json序列化一般会使用jackson包,通过ObjectMapper类来进行一些操作,比如将对象转化为byte数组或者将json串转化为对象。现在的大多数公司都将json作为服务器端返回的数据格式。比如调用一个服务器接口,通常的请求为xxx.json?a=xxx&b=xxx的形式。
3、FastJson序列化
fastjson 是由阿里巴巴开发的一个性能很好的Java 语言实现的 Json解析器和生成器。特点:速度快,测试表明fastjson具有极快的性能,超越任其他的Java json parser。功能强大,完全支持java bean、集合、Map、日期、Enum,支持范型和自省。无依赖,能够直接运行在Java SE 5.0以上版本 支持Android。使用时候需引入FastJson第三方jar包
4、ProtoBuff序列化
ProtocolBuffer是一种轻便高效的结构化数据存储格式,可以用于结构化数据序列化。适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。
优点:跨语言;序列化后数据占用空间比JSON小,JSON有一定的格式,在数据量上还有可以压缩的空间。
缺点:它以二进制的方式存储,无法直接读取编辑,除非你有 .proto 定义,否则无法直接读出 Protobuffer的任何内容。
9、Json
- JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
- JSON 是轻量级的文本数据交换格式
- JSON 独立于语言:JSON 使用 Javascript语法来描述数据对象,但是 JSON 仍然独立于语言和平台。JSON 解析器和 JSON 库支持许多不同的编程语言。 目前非常多的动态(PHP,JSP,.NET)编程语言都支持JSON。
- JSON 具有自我描述性,更易理解
与 XML 相同之处
- JSON 是纯文本
- JSON 具有"自我描述性"(人类可读)
- JSON 具有层级结构(值中存在值)
- JSON 可通过 JavaScript 进行解析
- JSON 数据可使用 AJAX 进行传输
与 XML 不同之处
- 没有结束标签
- 更短
- 读写的速度更快
- 能够使用内建的 JavaScript eval() 方法进行解析
- 使用数组
- 不使用保留字
10、 Angularjs
AngularJS 使得开发现代的单一页面应用程序(SPAs:Single Page Applications)变得更加容易。
- AngularJS 把应用程序数据绑定到 HTML 元素。
- AngularJS 可以克隆和重复 HTML 元素。
- AngularJS 可以隐藏和显示 HTML 元素。
- AngularJS 可以在 HTML 元素"背后"添加代码。
- AngularJS 支持输入验证。
11、 Redis使用场景
1、显示最新的项目列表
2、排行榜应用,取TOP N操作
3、删除与过滤
4、按照用户投票和时间排序
5、处理过期项目
6、计数
7、特定时间内的特定项目
8、查找某个值所在的区间(区间无重合) :(Sorted Set)
9、交集,并集,差集:(Set)
12、 算法
1、算法概要
算法是用于计算、数据处理和自动推理使用的。算法主要是做精确计算和表示一个有限长列的有效方法。算法一般包含清晰定义的指令用于计算函数。基本上也属于一种思考最简洁的方式。 2、算法特征 算法主要包含五个特征 2.1、有穷性; 是指算法必须能在执行有限个步骤后终止; 2.2、确切性; 算法的每一个步骤必须有确切的定义; 2.3、输入项; 一个算法输入有0或多个输入,以刻画预算对象的初始情况,所谓0就是初始化条件; 2.4、输出项; 反馈对数据加工后的结果。没有输出的算法无意义。 2.5、可行性; 算法中执行的任何计算都可以分步骤进行,每个步骤并在有限时间内完成。 3、算法常用的设计模式 主要有十个设计模式 3.1、完全遍历法 在验证一个问题集合时,且以验证正确性和最优性的时候,就会采用完全遍历法。但在便利的过程中就会消耗大量的内存。 3.2、不完全遍历法 当便利时占用的内存空间特别庞大时,可以使用不完全遍历法来实现。例如各种规则算法和搜索算法即是。 3.3、分治法 把一个问题分区成互相独立的部分,分别求解。分治法的好处在可以并行计算。
分治法所能解决的问题一般具有以下几个特征:
(1) 该问题的规模缩小到一定的程度就可以容易地解决; (2) 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质; (3) 利用该问题分解出的子问题的解可以合并为该问题的解; (4) 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。 3.4、动态规划法 当问题整体的最优解是由局部最优解组成的时候,会经常采用这种规划方法。用于求解包含重叠子问题的最优化问题的方法。 3.5、贪婪算法(也叫贪心算法) 常见的近似求解思路。当问题的整体最优解不是(或无法证明是)由局部最优解组成,且对解的最优性没有要求的时候,可以采用的一种方法。 3.6、线性规则法 问题是目标函数和约束条件都是线性的最优化 3.7、简并法 把一个问题通过逻辑或数学推理,简化成与之等价或者近似的、相对简单的模型,进而求解的方法。 3.8、穷举法 穷举法,或称为暴力破解法,其基本思路是:对于要解决的问题,列举出它的所有可能的情况,逐个判断有哪些是符合问题所要求的条件,从而得到问题的解。它也常用于对于密码的破译。 3.9、分枝界限法 分枝界限法是一个用途十分广泛的算法,运用这种算法的技巧性很强,不同类型的问题解法也各不相同。分支定界法的基本思想是对有约束条件的最优化问题的所有可行解(数目有限)空间进行搜索 3.10、回溯法 运用这种算法的技巧性很强,不同类型的问题解法也各不相同。分支定界法的基本思想是对有约束条件的最优化问题的所有可行解(数目有限)空间进行搜索13、 JAVA实现排序
最后总结一下:
稳定性:
1、稳定:冒泡排序、插入排序、归并排序和基数排序 2、 不稳定:选择排序、快速排序、希尔排序、堆排序 平均时间复杂度 1、O(n^2):直接插入排序,简单选择排序,冒泡排序。 2、在数据量特别大的时候,冒泡排序基本是最慢的。 3、在数据规模较小时(9W内),直接插入排序,简单选择排序差不多。当数据较大时,冒泡排序算法的时间代价最高。性能为O(n^2)的算法基本 上是相邻元素进行比较,基本上都是稳定的。 1、O(nlogn):快速排序,归并排序,希尔排序,堆排序。 2、其中,快排是最好的, 其次是归并和希尔,但数据量特别大的时候,归并排序很容易出现内存溢出的错误,如普通机器n>1000万时。 空间复杂度 1、O(1):冒泡排序、直接插入排序、二分插入排序、希尔排序、直接选择排序、堆排序 2、 O(n):归并排序 3、 O(nlog2n):快速排序 4、O(rd+n):基数排序 排序算法的选择 1、数据规模较小 (1)待排序列基本序的情况下,可以选择直接插入排序; (2)对稳定性不作要求宜用简单选择排序,对稳定性有要求宜用插入或冒泡 2、数据规模不是很大 (1)完全可以用内存空间,序列杂乱无序,对稳定性没有要求,快速排序,此时要付出log(N)的额外空间。 (2)序列本身可能有序,对稳定性有要求,空间允许下,宜用归并排序 3、数据规模很大 (1)对稳定性有求,则可考虑归并排序。 (2)对稳定性没要求,可以用快速排序。 4、数组初始基本有序的时候,宜用直接插入排序,否则,可以用希尔排序。代码的实现:
- package sort;
- /**
- * Package: sort
- *
- * File: JavaSorts.java
- *
- * Copyright @ 2015 Corpration Name
- *
- */
- public class JavaSorts {
- /**
- * 希尔排序
- * @param array
- */
- public static void ShellSort(int[] array){
- int d = array.length;
- do {
- d /= 2; //设置增量,通过设置增量来进行分组,分组后,每一组内采用直接插入排序
- OneShell(array, d);//一个增量对应一趟希尔排序
- } while (d > 1);
- }
- /**
- * 一趟希尔排序
- * @param array
- * @param d
- */
- public static void OneShell(int[] array,int d){
- for (int i = 0; i < array.length - d; i++) {
- int temp = array[i+d]; //array[i+d]的拷贝,每一次插入操作所以插入的值
- if (array[i] > array[i + d]) {
- int j = i;
- //此时分组为:j,j+d,j+2d,j+3d····,组内采用直接插入排序
- while(j >= 0 && array[j] > temp){
- array[j + d] = array[j]; //使用while循环寻找temp能够插入的位置,从右往左寻找,大于temp的往后移动
- j -= d;
- }
- array[j + d] = temp; //插入数据
- }
- }
- }
- /**
- * 快速排序
- * @param array
- * @param l
- * @param r
- */
- public static void QuickSort(int[] array,int l,int r){
- if (l < r) {
- int i = l,j = r,temp = array[l];
- while(i < j){
- while(i < j && array[j] > temp){
- j--; //从右边开始寻找比temp小的数
- }
- if(i < j){
- array[i++] = array[j]; //找到后,将这个数赋值到i位置上,然后i+1,因为下一轮寻找比temp大的数,从i+1位置开始
- }
- while(i < j && array[i] < temp){
- i++; //从左边寻找比temp大的数
- }
- if(i < j){
- array[j--] = array[i]; //找到后,将这个数赋值到j位置上,然后j-1,因为下一轮寻找比temp小的数从j-1位置开始
- }
- }
- array[i] = temp; //此时比temp小的数都移动到左边,比temp大的数都移动到了右边,最后将temp赋值到中间位置
- QuickSort(array, l, i - 1); //对temp左边的数进行递归
- QuickSort(array, i + 1, r); //对temp右边的数进行递归
- }
- }
- /**
- * 堆排序
- * @param array
- */
- public static void HeapSort(int[] array){
- for (int i = 0; i < array.length; i++) {
- BuildMaxHeap(array, array.length - 1 - i);
- Swap(array, 0, array.length - 1 - i);
- }
- }
- /**
- * 创建最大堆
- * @param array
- * @param lastOneIndex
- */
- public static void BuildMaxHeap(int[] array,int lastOneIndex){
- for (int i = (lastOneIndex - 1)/2; i >= 0; i--) {
- int k = i;
- while(2*k + 1 <= lastOneIndex){
- int bigIndex = 2*k + 1; //bigIndex用于记录一个节点树中最大数的索引
- if (bigIndex < lastOneIndex) { //满足这个条件,说明堆中有array[2*k+2]这个节点
- if (array[bigIndex] < array[bigIndex + 1]) {
- bigIndex++; //若满足这个条件,说明k节点下的右子节点大于左子结点,因而bigIndex加1
- }
- }
- if (array[k] < array[bigIndex]) {
- Swap(array, bigIndex, k); //若k节点小于它其中一个子节点,则与这个子节点交换值
- k = bigIndex; //交换完值后,此时k节点下面的bigIndex节点可能不满足堆的性质,所以赋值给k,重新进入下一轮while循环
- }else {
- break;//若k节点满足堆的性质,则直接跳出循环
- }
- }
- }
- }
- /**
- * 交换array中array[a]、array[b]
- * @param array
- * @param a
- * @param b
- */
- public static void Swap(int[] array,int a,int b){
- if (a < array.length && b < array.length) {
- int temp = array[a];
- array[a] = array[b];
- array[b] = temp;
- }
- }
- /**
- * 直接插入排序
- * @param array
- */
- public static void DirectInsertSort(int[] array){
- for (int i = 0; i < array.length - 1; i++) {
- int temp = array[i + 1];
- if (array[i] > array[i + 1]) {
- int j = i;
- while(j >= 0 && array[j] > temp){
- array[j + 1] = array[j];
- j--;
- }
- array[j + 1] = temp;
- }
- }
- }
- /**
- * 二分插入排序
- * @param array
- */
- public static void BinaryInsertSort(int[] array){
- for (int i = 0; i < array.length - 1; i++) {
- int temp = array[i + 1]; //需要插入的数
- if(array[i] > array[i + 1]){
- int l = 0; //有序队列中左边标识
- int r = i; //有序队列中右边标识
- while(l < r){
- int mid = (l + r) / 2; //永远指向l->r中间的那个值,中间值与temp(需要插入的值)比较
- if (array[mid] > temp) {
- r--; //通过while循环,二分折半搜索temp应该插入的位置
- }else {
- l++;
- }
- }
- //运行到这里,l==r,即是temp应该插入的位置是array[l](或者array[r])
- for (int j = i + 1; j > l; j--) {
- array[j] = array[j - 1]; //将l -> i的数都往后移动一位
- }
- array[l] = temp; //将temp插入到l位置
- }
- }
- }
- /**
- * 直接选择排序
- * @param array
- */
- public static void DirectSelectSort(int[] array){
- for (int i = 0; i < array.length - 1; i++) {
- int min = array[i];
- for (int j = i + 1; j < array.length; j++) {
- if (array[j] < min) {
- min = array[j];
- array[j] = array[i];
- array[i] = min;
- }
- }
- }
- }
- /**
- * 冒泡排序
- * @param array
- */
- public static void BubbleSort(int[] array){
- int temp = 0;
- for (int i = 0; i < array.length; i++) {
- for (int j = 0; j < array.length - 1; j++) {
- if (array[j] > array[j+1]) {
- temp = array[j];
- array[j] = array[j+1];
- array[j+1] = temp;
- }
- }
- }
- }
- /**
- * 归并排序
- * @param array
- */
- public static void MergeSort(int[] array){
- int left = 0;
- int right = array.length - 1;
- MergeSortRecursive(array, left, right); 000000000000000000000000000000000000000
- }
- /**
- * 归并排序的递归方法
- * @param array
- * @param left
- * @param right
- */
- public static void MergeSortRecursive(int[] array,int left,int right){
- if (left >= right) {
- return; //递归的停止判断,没有这个判断会报StackOverflowError
- }
- int mid = (left + right)/2;
- MergeSortRecursive(array, left, mid);
- MergeSortRecursive(array, mid+1, right);
- Merge(array, left, mid, right);
- }
- /**
- * 归并排序中合并方法
- * @param array
- * @param left
- * @param mid
- * @param right
- */
- public static void Merge(int[] array,int left,int mid,int right){
- int r_left = mid + 1; //需要合并数组中右边数组第一个数索引
- int[] tempArray = new int[array.length];//一个临时数组,用于合并时暂时存储
- int newIndex = left; //临时数组索引
- int tempLeft = left; //合并完了以后,用于复制数组的索引
- while(left <= mid && r_left <= right){ //将部分的数放入到临时数组中
- if (array[left] < array[r_left]) {
- tempArray[newIndex++] = array[left++];
- }else {
- tempArray[newIndex++] = array[r_left++];
- }
- }
- while (left <= mid) {
- tempArray[newIndex++] = array[left++]; //将左边还剩余的数放入临时数组(若需要合并的左边还剩余数)
- }
- while(r_left <= right){
- tempArray[newIndex++] = array[r_left++];//将右边还剩余的数放入临时数组(若需要和并的右边还剩余数)
- }
- while(tempLeft <= right){
- array[tempLeft] = tempArray[tempLeft++]; //将临时数组复制到array
- }
- }
- /**
- * 基数排序
- * @param array
- */
- public static void RadixSort(int[] array){
- int bits = FindMaxBit(array); //得到数组中最大的那个数的位数
- for (int i = 0; i < bits; i++) {
- OneBitSort(array, i+1); //一位基数的排序
- }
- }
- /**
- * 一位基数的排序
- * @param array
- * @param bit
- */
- public static void OneBitSort(int[] array,int bit){
- int[] tempArray = new int[array.length];
- int index = 0;
- int tempIndex = 0;
- for (int i = 0; i < 10; i++) {
- for (int j = 0; j < array.length; j++) {
- if (FindBitNum(array[j], bit) == i) {
- tempArray[index++] = array[j];
- }
- }
- }
- while(tempIndex < array.length){
- array[tempIndex] = tempArray[tempIndex++]; //复制数组
- }
- }
- /**
- * 得到某个数某一位的数(例如:num=1234,n=2,FindBitNum(1234,2)=3)
- * @param num
- * @param n
- * @return
- */
- public static int FindBitNum(int num,int n){
- int key1 = (int)Math.pow(10, n);
- int key2 = (int)Math.pow(10, n-1);
- num %= key1;
- num /= key2;
- return num;
- }
- /**
- * 得到一个数组中最大数的位数
- * @param array
- * @return
- */
- public static int FindMaxBit(int[] array){
- if (array == null || array.length ==0) {
- return 0;
- }
- int max = array[0];
- for (int i = 1; i < array.length; i++) {
- if (array[i] > max) {
- max = array[i];
- }
- }
- int bit = 0;
- while(max / 10 != 0 || max % 10 != 0){
- max /= 10;
- bit++;
- }
- return bit;
- }
- public static void main(String[] args) {
- System.out.println("冒泡排序:"+SortThreads.getBubbleSortTime());
- System.out.println("直接选择排序:"+SortThreads.getDirSelectSortTime());
- System.out.println("直接插入排序:"+SortThreads.getDirInsertSortTime());
- System.out.println("二分插入排序:"+SortThreads.getBinaryInsertSortTime());
- System.out.println("快速排序:"+SortThreads.getQuickSortTime());
- System.out.println("希尔排序:"+SortThreads.getShellSortTime());
- System.out.println("归并排序:"+SortThreads.getMergeSortTime());
- System.out.println("基数排序:"+SortThreads.getRadixSortTime());
- System.out.println("堆排序:"+SortThreads.getHeapSortTime());
- }
- }
14、 Springboot的优势
(1) 遵循"习惯优于配置"原则,使用Spirng Boot只需很少的配置,大部分时候可以使用默认配置;
(2)项目快速搭建,另外还可以无配置整合第三方框架;
(3)可完全不使用xml配置,只使用自动配置和Java Config;
(4)内嵌入Servlet如Tomcat容器,应用可用jar包运行(java -jar);
(5)运行中应用状态的监控
15、 Git使用
(1)首先Git是一种版本控制工具,但是与SVN等不同的是,它是分布式的。它并不需要一个集中的服务器。每个人电脑都是一个完整的独立仓库,团队中的每个人都可以从其他成员那里得到完整的仓库。但是为了满足出差,在家办公等需要,所以弄了一个集中的服务器。
(2)可以创建分支。Git默认的分支是master分支,一般做项目可以在master上放项目的稳定版本,而自己创建一个分支放beta版本。git branch
查看当前分支,git branch hk
创建新的分支hk,git checkout hk
切换到hk分支。在单独的分支上操作对其它分支没有影响。
(3)Git有工作区和暂存区之分。比如你在hk分支上修改了代码后,觉得功能加好了,那么可以用git add .
和git commit -m "message"
来把代码先提交到暂存区,再提交到工作区。如果你觉得这个版本稳定了,那么可以切换到master分支上用git merge hk
来合并hk分支。
(4)提交本地的master分支到中心服务器上,用git push origin master
命令。
(5)从中心服务器上下载库,用git pull origin master
16、 SpringMVC执行流程
Spring MVC是Spring提供的一个强大而灵活的Web框架,借助于注解,Spinrg MVC提供了几乎是POJO的开发模式,使得控制器的开发和测试更加简单这些控制器一般不直接处理请求,而是将其委托给Spring上下文中的其他bean,通过功能,这些bean被注入到控制器中。
Spring MVC主要由DispatcherServlet,处理器映射,处理器(控制器),试图解析器,试图组成。两个核心是:处理器映射(选择使用那个控制器来处理请求);视图解析器(选择结果应该如何渲染)
原理:
核心架构的具体流程步骤如下:
1、首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行
处理,作为统一访问点,进行全局的流程控制;
2、DispatcherServlet——>HandlerMapping, HandlerMapping 将会把请求映射为HandlerExecutionChain 对象(包含一
个Handler 处理器(页面控制器)对象、多个HandlerInterceptor 拦截器)对象,通过这种策略模式,很容易添加新
的映射策略;
3、DispatcherServlet——>HandlerAdapter,HandlerAdapter 将会把处理器包装为适配器,从而支持多种类型的处理器,
即适配器设计模式的应用,从而很容易支持很多类型的处理器;
4、HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter 将会根据适配的结果调用真正的处理器的功能处
理方法,完成功能处理;并返回一个ModelAndView 对象(包含模型数据、逻辑视图名);
5、ModelAndView的逻辑视图名——> ViewResolver, ViewResolver 将把逻辑视图名解析为具体的View,通过这种策
略模式,很容易更换其他视图技术;
6、View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此
很容易支持其他视图技术;
7、返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。
17、 Mybatis配置
网址:http://blog.csdn.net/qh_java/article/details/51601139
18、 快速排序
1. 单轴快速排序的基本原理
快速排序的基本思想就是从一个数组中任意挑选一个元素(通常来说会选择最左边的元素)作为中轴元素,将剩下的元素以中轴元素作为比较的标准,将小于等于中轴元素的放到中轴元素的左边,将大于中轴元素的放到中轴元素的右边,然后以当前中轴元素的位置为界,将左半部分子数组和右半部分子数组看成两个新的数组,重复上述操作,直到子数组的元素个数小于等于1(因为一个元素的数组必定是有序的)。
以下的代码中会常常使用交换数组中两个元素值的Swap方法,其代码如下
public
static
void
Swap(int[] A, int
i, int
j){
int
tmp;
tmp = A[i];
A[i] = A[j];
A[j] = tmp;
}
19、 线程锁
1.在多线程环境中,当我们需要保持线程同步时,通常通过锁来实现。
互斥锁的使用过程中,主要有
第一:线程锁的初始化,pthread_mutex_init 第二:线程锁的释放,pthread_mutex_destory 第三:线程锁的加锁操作,pthread_mutex_lock 第四:线程锁的解锁操作,pthread_mutex_unlock网址:http://blog.csdn.net/u011857683/article/details/52336805
20、 Js实现更换图片
<script>
//
通过id值获得元素的函数
function $(id){
return document.getElementById(id);
}
//
初始化函数
function initial(){
olLi=document.getElementsByTagName('ol')[0].getElementsByTagName('li');//
获取ol下的li
ol=$('tab');//
获取ol元素
theImg=$('theImg');
//
五张图片的地址
addressPic=['01.jpg','02.jpg','03.jpg','04.jpg','05.jpg'];
//
遍历ol下的li
for(var i=0;i<olLi.length;i++){
//
依次给每个li绑定mouseover事件,该事件执行切换图片的函数
olLi[i].addEventListener('mouseover',changePicture,false);
olLi[i].index=i;//
设置ol li的index序列号
}
}
//
切换图片
function changePicture(e){
e.target.className="current";//
将选中的ol下的li的class属性设置为current,e.target代表选中的li
//
清除ol里的空白节点
cleanWhitespace(ol);
//
删除除当前选中的li外其他li的class属性值
nextNode=e.target.nextSibling;//
当前节点的下一个节点
lastNode=e.target.previousSibling;//
当前节点的前一个节点
while(nextNode){//
将当前节点后所有的兄弟节点的class属性清除
nextNode.setAttribute('class','');
nextNode=nextNode.nextSibling;
}
while(lastNode){//
将当前节点前面所有的兄弟节点的class属性清除
lastNode.className='';
lastNode=lastNode.previousSibling;
}
//
实现切换图片的功能
theImg.src=addressPic[this.index];
}
//
清除ol下的空白节点
function cleanWhitespace(oElement)
{
for(var i=0;i<oElement.childNodes.length;i++){
var node=oElement.childNodes[i];
if(node.nodeType==3 && !/\S/.test(node.nodeValue)){
node.parentNode.removeChild(node)
}
}
}
//
给窗体绑定load事件,执行初始化函数initial()
window.addEventListener('load',initial,false);
</script>
21、 什么叫静态页面
静态网页的网址形式通常为:www.example.com/eg/eg.htm ,也就是以.htm、.html、.shtml、.xml等为后缀的。在HTML格式的网页上,也可以出现各种动态的效果,如.GIF格式的动画、FLASH、滚动字母等,这些“动态效果”只是视觉上的,与下面将要介绍的动态网页是不同的概念。
静态网页的特点简要归纳如下:
(1)静态网页每个网页都有一个固定的URL,且网页URL以.htm、.html、.shtml等常见形式为后缀,而不含 静态与动态网页
有“?”;
(2)网页内容一经发布到网站服务器上,无论是否有用户访问,每个静态网页的内容都是保存在网站服务器上的,也就是说,静态网页是实实在在保存在服务器上的文件,每个网页都是一个独立的文件;
(3)静态网页的内容相对稳定,因此容易被搜索引擎检索;
(4)静态网页没有数据库的支持,在网站制作和维护方面工作量较大,因此当网站信息量很大时完全依靠静态网页制作方式比较困难;
(5)静态网页的交互性较差,在功能方面有较大的限制。
静态网页,动态网页主要根据网页制作的语言来区分:
静态网页使用语言:HTML(超文本标记语言)
动态网页使用语言:HTML+ASP 或 HTML+PHP 或 HTML+JSP 等。
静态网页与动态的区别
程序是否在服务器端运行,是重要标志。在服务器端运行的程序、网页、组件,属于动态网页,它们会随不同客户、不同时间,返回不同的网页,例如ASP、PHP、JSP、ASP.net、CGI等。运行于客户端的程序、网页、插件、组件,属于静态网页,例如html页、Flash、JavaScript、VBScript等等,它们是永远不变的。
静态网页和动态网页各有特点,网站采用动态网页还是静态网页主要取决于网站的功能需求和网站内容的多少,如果网站功能比较简单,内容更新量不是很大,采用纯静态网页的方式会更简单,反之一般要采用动态网页技术来实现。
静态网页是相对于动态网页而言,是指没有后台数据库、不含程序和不可交互的网页。你编的是什么它显示的就是什么、不会有任何改变。静态网页相对更新起来比较麻烦,适用于一般更新较少的展示型网站。
静态网页是标准的HTML文件,它的文件扩展名是.htm或.html,可以包含文本、图像、声音、FLASH动画、客户端脚本和ActiveX控件及JAVA小程序等。尽管在这种网页上使用这些对象后可以使网页动感十足,但是,这种网页不包含在服务器端运行的任何脚本,网页上的每一行代码都是由网页设计人员预先编写好后,放置到Web服务器上的,在发送到客户端的浏览器上后不再发生任何变化,因此称其为静态网页。
静态网页是网站建设的基础,静态网页和动态网页之间也并不矛盾,为了网站适应搜索引擎检索的需要,即使采用动态网站技术,也可以将网页内容转化为静态网页发布。
动态网站也可以采用静动结合的原则,适合采用动态网页的地方用动态网页,如果必要使用静态网页, 静态网页相关图片
22、 Session共享
1. 基于NFS的Session共享
NFS是Net FileSystem的简称,将共享目录服务器mount到各频道服务器的本地session目录即可,缺点是NFS依托于复杂的安全机制和文件系统,因此并发效率不高,
2. 基于数据库的Session共享
首选当然是大名鼎鼎的数据库,并且建议使用内存表Heap,提高session操作的读写效率。它的缺点在于session的并发读写能力取决于Mysql数据库的性能,同时需要自己实现session淘汰逻辑,以便定时从数据表中更新、删除 session记录,
3. 基于Cookie的Session共享
原理是将全站用户的Session信息加密、序列化后以Cookie的方式,统一种植在根域名下(如:.host.com),利用浏览器访问该根域名下的所有二级域名站点时,会传递与之域名对应的所有Cookie内容的特性,从而实现用户的Cookie化Session 在多服务间的共享访问。
4. 基于Memcache的Session共享
由于是一款基于多路异步I/O技术的内存共享系统,简单的Key + Value数据存储模式使得代码逻辑小巧高效,因此在并发处理能力上占据了绝对优势,目前本人所经历的项目达到2000/秒 平均查询,并且服务器CPU消耗依然不到10%。
23、 自旋锁 迭代锁
自旋锁是专为防止多处理器并发而引入的一种锁,它在中大量应用于等部分(对于单处理器来说,防止中断处理中的并发可简单采用关闭中断的方式,即在中关闭/打开中断标志位,不需要自旋锁)。
24、 单例
单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。单例模式是设计模式中最简单的形式之一。这一模式的目的是使得类的一个对象成为系统中的唯一实例
25、 分布式单例
26、 系统与系统之间如何保持单例
27、 Nginx实现原理
Nginx由内核和模块组成,其中,内核的设计非常微小和简洁,完成的工作也非常简单,仅仅通过查找配置文件将客户端请求映射到一个location block(location是Nginx配置中的一个指令,用于URL匹配),而在这个location中所配置的每个指令将会启动不同的模块去完成相应的工作。
Nginx的模块从结构上分为核心模块、基础模块和第三方模块:
核心模块:HTTP模块、EVENT模块和MAIL模块
基础模块:HTTP Access模块、HTTP FastCGI模块、HTTP Proxy模块和HTTP Rewrite模块,
第三方模块:HTTP Upstream Request Hash模块、Notice模块和HTTP Access Key模块。
用户根据自己的需要开发的模块都属于第三方模块。正是有了这么多模块的支撑,Nginx的功能才会如此强大。
28、 阻塞与非阻塞的区别
阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.
阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
29、 线程共享
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
30、 堆栈空间
注意:其实堆栈本身就是栈,只是换了个抽象的名字。
堆栈的特性: 最后一个放入堆栈中的物体总是被最先拿出来, 这个特性通常称为后进先出(LIFO)队列。 堆栈中定义了一些操作。 两个最重要的是PUSH和POP。 PUSH操作在堆栈的顶部加入一 个元素。POP操作相反, 在堆栈顶部移去一个元素, 并将堆栈的大小减一。
队列:什么是队列?又该怎么理解呢?
①队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。
②队列中没有元素时,称为空队列。
③建立顺序队列结构必须为其静态分配或动态申请一片连续的存储空间,并设置两个指针进行管理。一个是队头指针front,它指向队头元素;另一个是队尾指针rear,它指向下一个入队元素的存储位置。
④队列采用的FIFO(first in first out),新元素(等待进入队列的元素)总是被插入到链表的尾部,而读取的时候总是从链表的头部开始读取。每次读取一个元素,释放一个元素。所谓的动态创建,动态释放。因而也不存在溢出等问题。由于链表由结构体间接而成,遍历也方便。(先进先出)
堆、栈区别总结:
1.堆栈空间分配
①栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
②堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。
2.堆栈缓存方式
①栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放。
②堆则是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。
3.堆栈数据结构区别
①堆(数据结构):堆可以被看成是一棵树,如:堆排序。
②栈(数据结构):一种先进后出的数据结构。
31、 Hashmap,tablemap,treemap,map的对比
共同点
HashMap,LinkedHashMap,TreeMap都属于Map;Map 主要用于存储键(key)值(value)对,根据键得到值,因此键不允许键重复,但允许值重复。
不同点
1、HashMap键无序,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度,在Map 中插入、删除和定位元素,HashMap 是最好的选择;
2、LinkedHashMap 是HashMap的一个子类,键保存了插入的顺序,使用Iterator遍历时,得到的也是插入顺序的记录; 3、TreeMap默认按键的升序排序,可以定制。 4、HashTable 线程安全,键不能为null,与HashMap类似,但效率较低,HashMap如果需要实现同步,可以使用Collections. synchronizedMap或ConcurrentHashMap 。32、 List集合的区别
Vector、ArrayList都是以类似数组的形式存储在内存中,LinkedList则以链表的形式进行存储。
List中的元素有序、允许有重复的元素,Set中的元素无序、不允许有重复元素。
Vector线程同步,ArrayList、LinkedList线程不同步。
LinkedList适合指定位置插入、删除操作,不适合查找;ArrayList、Vector适合查找,不适合指定位置的插入、删除操作。
ArrayList在元素填满容器时会自动扩充容器大小的50%,而Vector则是100%,因此ArrayList更节省空间。
33、 treemap和安全集合会产生什么影响
34、 spring事物
Spring事务 的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行:
获取连接 Connection con = DriverManager.getConnection() 开启事务con.setAutoCommit(true/false); 执行CRUD 提交事务/回滚事务 con.commit() / con.rollback(); 关闭连接 conn.close(); 使用Spring的事务管理功能后,我们可以不再写步骤 2 和 4 的代码,而是由Spirng 自动完成。 那么Spring是如何在我们书写的 CRUD 之前和之后开启事务和关闭事务的呢?解决这个问题,也就可以从整体上理解Spring的事务管理实现原理了。下面简单地介绍下,注解方式为例子 配置文件开启注解驱动,在相关的类和方法上通过注解@Transactional标识。 spring 在启动的时候会去解析生成相关的bean,这时候会查看拥有相关注解的类和方法,并且为这些类和方法生成代理,并根据@Transaction的相关参数进行相关配置注入,这样就在代理中为我们把相关的事务处理掉了(开启正常提交事务,异常回滚事务)。35、 数据库事物
(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列,要么完全地执行,要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。事务是数据库运行中的逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理。
36、 怎么配置spring事物
1、传统使用JDBC的事务管理
以往使用JDBC进行数据操作,使用DataSource,从数据源中得到Connection,我们知道数据源是线程安全的,而连接不是线程安全的,所以对每个请求都是从数据源中重新取出一个连接。一般的数据源由容器进行管理,包括连接池。例如TOMCAT,WEBSPHERE,WEBLOGIC等这些J2EE商业容器都提供了这个功能。2、Spring提供的编程式的事务处理
Spring提供了几个关于事务处理的类:TransactionDefinition //事务属性定义 TranscationStatus //代表了当前的事务,可以提交,回滚。 PlatformTransactionManager这个是spring提供的用于管理事务的基础接口,其下有一个实现的抽象类AbstractPlatformTransactionManager,我们使用的事务管理类例如DataSourceTransactionManager等都是这个类的子类。Spring声明式事务处理
Spring声明式事务处理也主要使用了IoC,AOP思想,提供了TransactionInterceptor拦截器和常用的代理类TransactionProxyFactoryBean,可以直接对组件进行事务代理。
37、 设计模式
单例模式有以下特点: 1、单例类只能有一个实例。 2、单例类必须自己创建自己的唯一实例。 3、单例类必须给所有其他对象提供这一实例。
代理模式:
代理模式的三种角色:
抽象角色(声明真实对象和代理对象的共同接口)
代理角色(代理角色中提供与真实对象相同的接口以便在任何时候可都能代理真实对象,同时附加其他操作,相当于真实对象进行封装)
真实角色:代理角色所代表的真对象,是我们最终要引用的对象
好处:就是对外部提供统一的接口方法而代理类在接口中实现对真实类的附加操作行为,从而可以在不影响外部调用的情况下,进行系统扩展。
工厂模式:
主要解决:接口选择的问题
如何解决:让其子类实现工厂接口,返回的也是一个抽象的产品。
优点:如果想创建对象,只要知道名字即可;扩展性高,如果想要增加一种产品,只需扩展一个工厂类即可;不关心其内部的具体实现,只关心接口的作用即可
缺点:每次增加一个工厂类,需要增加个具体类和对象实现工厂,当时的系统中类的个数成倍增加,在一定层都上增加了系统的复杂度,同时也增加了系统具体类的依赖。
观察者模式:
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。
意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。
如何解决:使用面向对象技术,可以将这种依赖关系弱化。
关键代码:在抽象类里有一个 ArrayList 存放观察者们。
应用实例: 1、拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价。 2、西游记里面悟空请求菩萨降服红孩儿,菩萨洒了一地水招来一个老乌龟,这个乌龟就是观察者,他观察菩萨洒水这个动作。
优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。
缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
38、 sleep wait的区别
1.sleep和wait都是用来进行线程控制,他们最大本质的区别是:
sleep()不释放同步锁,wait()释放同步锁. sleep(milliseconds)可以用时间指定来使他自动醒过来,如果时间不到你只能调用interreput()来强行打断; wait()可以用notify()直接唤起.
2.sleep是Thread类的静态方法。
sleep的作用是让线程休眠制定的时间,在时间到达时恢复,也就是说sleep将在接到时间到达事件事恢复线程执行,例如: try{ System.out.println("I'm going to bed"); Thread.sleep(1000); System.out.println("I wake up"); } catch(IntrruptedException e) { }
wait是Object的方法,也就是说可以对任意一个对象调用wait方法,调用wait方法将会将调用者的线程挂起,直到其他线程调用同一个对象的notify方法才会重新激活调用者,例如: try{ obj.wait }
catch(InterrputedException e) { } 3. sleep()是让某个线程暂停运行一段时间,其控制范围是由当前线程决定, wait()是由某个确定的对象来调用的。 sleep和wait的区别有: 1,这两个方法来自不同的类分别是Thread和Object 2,最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。 3,wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在 任何地方使用 synchronized(x){ x.notify() //或者wait() }
4,sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常
39、 js生成excel表
/* 此样式仅用于浏览器页面效果,Excel不会分离表格边框,不需要此样式 */
table {
border-collapse: collapse;
}
学生成绩表
编号
学号
姓名
性别
年龄
成绩
语文
数学
英语
1
2016001
张三
男
13
85
94
77
2
2016002
李四
女
12
96
84
89
导出表格
// 使用outerHTML属性获取整个table元素的HTML代码(包括
var html = " " + document.getElementsByTagName("table")[0].outerHTML + "";
// 实例化一个Blob对象,其构造函数的第一个参数是包含文件内容的数组,第二个参数是包含文件类型属性的对象
var blob = new Blob([html], { type: "application/vnd.ms-excel" });
var a = document.getElementsByTagName("a")[0];
// 利用URL.createObjectURL()方法为a元素生成blob URL a.href = URL.createObjectURL(blob);
// 设置文件名,目前只有Chrome和FireFox支持此属性 a.download = "学生成绩表.xls";
40、 easyUI
41.选择排序
他的工作原理是每一次从待排序的元素中最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数组元素排完,选择排序是不稳定的排序方法(比如序列[5,5,3],第一次将第一个5与3交换,导致第一个5挪到第二个5后边)
public void sort(int[] sort){
for(int i=0;i<sort.length;i++){
for(int j=i+1;j<sort.length;j++){
if(sort[i]>sort[j]){
int temp=sort[j];
sort[j]=sort[i];
sort[i]=temp;
}
}
}
42.Map实现原理
经过排序了的二元组的集合,Map中的每个元素都是由两个值组成,其中Key(键值,一个Map集合中键值是必须的),是在排序或搜索时使用,他的值可以在容器中重新获取,而另一个是该元素关联的数值,比如除了可以ar[43]=”overripe”这样找到一个数据,Map还可以通过ar[“banana”]=“overripe”这样的方法找到一个数据
43.Tomcat集群冲突有什么影响
a) 集群冲突的话就只能运行一个tomcat而不能运行多个tomcat,所以要改端口号,不让集群有冲突!
b) DNS轮询 当集群中某台服务器停止之后,用户由于dns缓存的缘故,便无法访问服务,必须等到dns解析更新,或者这台服务器重新启动。还有就是必须把集群中的所有服务端口暴露给外界,没有用apache做前置代理的方式安全,并且占用大量公网IP地址,而且tomcat还要负责处理静态网页资源,影响效率
c) R-proxy(反向代理)当其中一台tomcat停止运行的时候,apache仍然会转发请求过去,导致502网关错误。但是只要服务器再启动就不存在这个问题。
d) mod_jk 当停止掉的tomcat服务器再次启动的时候,Apache检测不到,仍然不会转发请求过去。
44.Spring的实现原理
e) Spring内部最核心的就是IOC了,动态注入,让一个对象的创建不用再new,可以自动的生产,这其实利用了java的反射,反射其实就是在运行时动态的去创建,调用对象,Spring就是在运行时,跟XML Spring的配置文件来动态创建对象和调用对象里的方法。
f) Spring还有一个核心就是AOP,这个是面向切面编程,可以为某一对象进行监督和控制(也就是在调用这类对象的具体方法的前后去调用你指定的模块)从而达到对一个模块扩充的功能,这些都是通过配置类达到的
g) Spring目的:就是让对象与对象之间的关系没有通过代码来关联,都是通过配置类说明管理的(Spring根据这些配置,内部通过反射去动态组装对象)
45.Spring Boot配置与不配置的区别
SpringBoot理念就是零配置编程。
SpringBootServletInitializer初始化servlet代替了web.xml,servlet3.0不需要web.xml。
46.公平和非公平锁
所谓公平锁指的是哪个线程先运行,那就可以先得到锁。非公平锁是不管线 程是否是先运行,都是随机获得锁的。
在公平的锁上,线程按照他们发出请求的顺序获取锁,但在非公平锁上,则允许‘插队’:当一个线程请求非公平锁时,如果在发出请求的同时该锁变成可用状态,那么这个线程会跳过队列中所有的等待线程而获得锁。
47.orcale调用存储过程
无参数存储过程的使用:
· 例:创建一个存储过程,用于向数据库中插入一条记录。
第一步:创建
· CREATE OR REPLACE PROCEDURE pro_1
· IS
· Begin
· insert into person values (11,'aa','aav');
· End;
第二步:在sql*plus中执行该过程
· exec pro_1;
第三步:通过JDBC使用存储过程。
· private Connection conn = null;
· private ResultSet rs = null;
· private CallableStatement state = null;
· //调用一个无参数的存储过程
· public void testPro()
· {
· conn = Tools.getConnection();
· try {
· state = conn.prepareCall("{call pro_1}");
· state.execute();
· } catch (Exception e) {
· // TODO Auto-generated catch block
· e.printStackTrace();
· }
· }
48.高并发
域,这个指标和吞吐量区分的没有这么明显。
并发用户数:同时承载正常使用系什么是高并发
高并发(High Concurrency)是互联网分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计保证系统能够同时并行处理很多请求。
高并发相关常用的一些指标有响应时间(Response Time),吞吐量(Throughput),每秒查询率QPS(Query Per Second),并发用户数等。
响应时间:系统对请求做出响应的时间。
吞吐量:单位时间内处理的请求数量。
QPS:每秒响应请求数。在互联网领统功能的用户数量。例如一个即时通讯系统,同时在线量一定程度上代表了系统的并发用户数
49.点对点和订阅发布的区别
JMS中定义
JMS规范目前支持两种消息模型:点对点(point to point, queue)和发布/订阅(publish/subscribe,topic)。
点对点: 消息生产者生产消息发送到queue中,然后消息消费者从queue中取出并且消费消息。这里要注意: 消息被消费以后,queue中不再有存储,所以消息消费者不可能消费到已经被消费的消息。 Queue支持存在多个消费者,但是对一个消息而言,只会有一个消费者可以消费。 发布/订阅 消息生产者(发布)将消息发布到topic中,同时有多个消息消费者(订阅)消费该消息。和点对点方式不同,发布到topic的消息会被所有订阅者消费。50.Websocket
WebSocket 事件
事件 | 事件处理程序 | 描述 |
open | Socket.onopen | 连接建立时触发 |
message | Socket.onmessage | 客户端接收服务端数据时触发 |
error | Socket.onerror | 通信发生错误时触发 |
close | Socket.onclose | 连接关闭时触发 |
HTML5 WebSocket
WebSocket是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。
当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。
51.dubbo架构图
1.服务接口层:该层与实际业务逻辑有关,根据服务消费方和服务提供方的业务设计,实现对应的接口。
2.配置层:对外配置接口,以ServiceConfig和ReferenceConfig为中心,可以直接new配置类,也可以根据spring解析配置生成配置类。
3.服务注册层:封装服务地址的注册和发现,以服务URL为中心,扩展接口为RegistryFactory、Registry、RegistryService,可能没有服务注册中心,此时服务提供方直接暴露 服务。
4.服务代理层:服务接口通明代理,生成服务的客户端Stub和服务端Skeleton,以ServiceProxy为中心,扩展接口ProxyFactory。
5.集群层:封装多个提供者的路由和负载均衡,并桥接注册中 心,以Invoker为中心,扩展接口为Cluster、Directory、Router 和LoadBalance,将多个服务提供方组合为 一个服 务提供方, 实现对服务消费通明。只需要与一个服务提供方进行交互。
6.监控层:RPC调用时间和次数监控,以Statistics为中心,扩展接口MonitorFactory、Monitor和MonitorService。
7.远程调用层:封装RPC调用,以Invocation和Result为中心,扩展接口为Protocol、Invoker和Exporter。Protocol是服务域,它是Invoker暴露和引用的主功能入口,它负责 Invoker的生命周期管理。Invoker是实体域,它是Dubbo的核心模型,其他模型都是向它靠拢,或转换成它,它代表一个可执行体,可向它发起Invoker调用,它有可能是一个本 地实现,也有可能是一个远程实现,也有可能是一个集群实现。
8.信息交换层:封装请求响应模式,同步转异步,以Request和Response为中心,扩展接口为Exchanger和ExchangeChannel,ExchangeClient和ExchangeServer。
9.网络传输层:抽象和mina和netty为统一接口,以Message为中心,扩展接口为Channel、Transporter、Client、Server和Codec。
10.数据序列化层:可复用的一些工具,扩展接口为Serialization、ObjectInput,ObejctOutput和ThreadPool。
52.redis持久化方式(两种)
1)RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
2)AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。
53.项目上线后问题
1.新流程的执行问题。在实施阶段设计得很好的流程在实际使用过程中是否能够得到很好的执行
2.系统调整的问题。实施项目后,计划模式及业务流程进行了调整,这个时候系统中设定的某些参数和基础数据不一定很准确,上线之后,随着系统的使用,这些参数的问题会暴 露 出来,实施阶段,这些参数和基础数据的设定是顾问协助完成的。系统运维阶段,如何对这些参数进行调整使其符合企业的实际是一个非常重要的问题
3.数据的准确性问题。我们知道,在手工阶段,同一个数据可以通过对不同业务部门提交的报表中进行分析比较。实施ERP后,数据的来源基本上就唯一了,数据源头的错误会导致 后续一连串的数据错误。
4.队伍的问题。随着系统的上线,顾问的撤出,这时候企业需要自己的团队面对所有可能出现的问题。这个时候,企业自己的团队是否已经准备好了是系统能否正常运行的关键。
5.资金的问题 项目的后续维护成本绝对不是可以忽略不计的。人员的培训、系统的维护与优化、硬件的维护等等,这些加起来是一笔不小的费用。
54.不用dubbo使用springcloud的好处
相同之处,它们两都具备分布式服务治理相关的功能,都能够提供服务注册、发现、路由、负载均衡等。说到这,Dubbo的功能好像也就这么多了,但是Spring Cloud是提供了一 整套企业级分布式云应用的完美解决方案,能够结合Spring Boot,Docker实现快速开发的目的,所以说Dubbo只有Spring Cloud的一部分RPC功能,而且也谈不上谁好谁坏。不过 Dubbo项目现已停止了更新,淘宝内部由hsf替代dubbo,我想这会有更多人倾向Spring Cloud了。
从开发角度上说,Dubbo常与Spring、zookeeper结合,而且实现只是通过xml来配置服务地址、名称、端口,代码的侵入性是很小的,相对Spring Cloud,它的实现需要类注解等多少具有一定侵入性。
55.spring传播特性
spring通过事务传播 spring的六种事务传播特性:
1. PROPAGATION_REQUIRED: 如果存在一个事务,则支持当前事务。如果没有事务则开启
2. PROPAGATION_SUPPORTS: 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行
3. PROPAGATION_MANDATORY: 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
4. PROPAGATION_REQUIRES_NEW: 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
5. PROPAGATION_NOT_SUPPORTED: 总是非事务地执行,并挂起任何存在的事务。
6. PROPAGATION_NEVER: 总是非事务地执行,如果存在一个活动事务,则抛出异常
56.经纬度计算(百度地图插件)
- i. 经纬度:通过经度(longitude)和纬度(latitude)描述的地球上的某个位置。
- ii. 平面坐标:投影之后的坐标(用x和y描述),用于在平面上标识某个位置。
- iii. 像素坐标:描述不同级别下地图上某点的位置。
- iv. 图块坐标:地图图块编号(用x和y描述)。
- v. 可视区域坐标:地图可视区域的坐标系(用x和y描述)。
- vi. 覆盖物坐标:覆盖物相对于容器的坐标(用x和y描述)。
57.订单状态监听(电商项目)
顾客订单
一. 销售输入(小订单模式):
1. 校验代理商或者店主商品库存, 校验输入的商品总数不能为负数
2. 减去代理商或者店主的库存
3. 添加一条订单记录(小订单)
4. 更新顾客消费总额(每添加一个小订单,消费总额更新一次)
5. 更新顾客最近消费记录(最近消费商品,最近购买时间, 购买次数购买次数(添加一个大单sales加1,销售取消时不做减操作))
二. 销售取消(小订单)
1. 校验顾客购买的产品数量,取消的数量不能大于顾客购买商品剩余的数量, 校验输入的商品总数不能为负数。
2. 将所退的商品增加到代理商或者店主库存
3. 销售取消单价重置为负数,总价格也为负数
4. 增加一条销售取消记录
5. 更新用户消费总额(每取消一个小订单,消费总额更新一次)
代理商订单(走大订单流程)
订单状态:
1. 待确认(没有任何代理商确认过的)
2. 已确认(有一个代理商确认过但还有代理商没确认的)
3.配送准备中(已确认)(所有代理商都确认过了)
4.确认收款(总部已经收款的)
5. 配送中(总部已经发货的,确认收款之后的5天后自动在前端显示配送中的状态)
6. 订单完成(总部发货后已经10天自动完成订单)
7.订单取消(相当于将订单作废)
一. 下单流程:
1. 查询商品列表
2. 勾选商品,添加到购物车,购物车中商品数量加减(购物车中有这个商品,则累计数据,购物车中没有则新增一条记录)注意:这个时候不校验库存
3. 提交订单,勾选地址(没有的话就创建一个新的地址)。
4. 订单确认提交
5. 商品库存校验,商品是否被删除校验
6. 生成大订单(返回大订单id,将但订单id加入到小订单中)
7. 遍历添加小订单
8. 商品减库存,加销量
9. 将购物车中的订单转化为订单状态
二. 订单定时器
1. 确认收款之后的5天后自动在前端显示配送中的状态
2. 确认收款后的10天后自动在前端显示订单结束
3. 订单结束后增加代理商或者店主商品库存
4. 更新代理商或者店主的最近购买记录。
58.观察者模式(Observer)
观察者模式是java中的23种设计模式之一,观察者模式是对象的行为模式,又叫发布,订阅,模型,视图,源,监听器,从属者/模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自动更新自己。观察者的出现是为了是系统能够易于复用,应该选择低耦合的设计方案。观察者模式涉及到的角色有“抽象主题角色”“具体主题角色”“抽象观察者角色”“具体观察者角色”
59.负载均衡
Load Balancer是整个集群系统的前端,负责把客户请求转发到Real Server上。Load Balancer通过Ldirectord监测各Real Server的健康状况。在Real Server不可用时把它从群中剔除,恢复时重新加入。
Backup是备份Load Balancer,当Load Balancer不可用时接替它,成为实际的Load Balancer。
60.拆表原则
1.能不分就不分
2.数据量太大,正常的运维影响正常业务访问
3.表设计不合理,需要对某些字段垂直拆分
4.某些数据表出现了无穷增长
5.安全性和可用性的考虑
6.业务耦合性考虑
61.Dubbo的作用
Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。简单的说,dubbo就是个服务框架,如果没有分布式的需求,其实是不需要用的,只有在分布式的时候,才有dubbo这样的分布式服务框架的需求。
Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合)。
62.Jvm
Java程序的跨平台特性主要是指字节码文件可以在任何具有Java虚拟 机的计算机或者电子设备上运行,Java虚拟机中的Java解释器负责将字节 码文件解释成为特定的机器码进行运行。因此在运行时,Java源程序需要通 过编译器编译成为.class文件。
JVM是JRE的一部分。它是一个虚构出来的计算机,是通过在实际的计 算机上仿真模拟各种计算机功能来实现的。JVM有自己完善的硬件架构,如 处理器、堆栈、寄存器等,还具有相应的指令系统
63.servlet配置
Servlet和jsp功能一致,也就是说,servlet可以被外部访问,那么要访问它,就需要通过一个地址,因此只有通过web的地址映射来访问。
web.xmll
<servlet>
<servlet-name>自己定义名字</servlet-name>
<servlet-class>servlet文件的路径</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>和上边定义的名字保持一致</servlet-name>
<url-pattern>地址名</url-patturn>
</servlet-mapping>
64.Fastdfs
FastDFS是用c语言编写的一款开源的分布式文件系统。FastDFS为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。
FastDFS架构包括 Tracker server和Storage server。客户端请求Tracker server进行文件上传、下载,通过Tracker server调度最终由Storage server完成文件上传和下载。
65.sharding-jdbc
Sharding-JDBC直接封装JDBC API,可以理解为增强版的JDBC驱动,旧代码迁移成本几乎为零:
Sharding-JDBC定位为轻量Java框架,使用客户端直连数据库,以jar包形式提供服务,无proxy代理层,无需额外部署,无其他依赖,DBA也无需改变原有的运维方式。
66.redis5种基本数据类型
l 字符串类型(string),字符串类型是Redis的最基本类型,它可以存储任何形式的字符串。其它的四种类型都是字符串类型的不同形式。
l 散列类型(hash),
l 列表类型(list),内部使用双向链表实现,所以获取越接近两端的元素速度越快,但通过索引访问时会比较慢
l 集合类型(set),集合类型值具有唯一性,常用操作是向集合添加、删除、判断某个值是否存在,集合内部是使用值为空的散列表实现的。
l 有序集合类型(zset)
67.hibernate和mybatis应用场景
Mybatis应用场景:
需求多变的互联网项目,例如电商项目。
Hibernate应用场景:
需求明确、业务固定的项目,例如OA项目、ERP项目等。
68.stuats2与springmvc的对比
l Struts2是类级别的拦截, 一个类对应一个request上下文,SpringMVC是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上SpringMVC就容易实现restful url,而struts2的架构实现起来要费劲,因为Struts2中Action的一个方法可以对应一个url,而其类属性却被所有方法共享,这也就无法用注解或其他方式标识其所属方法了。
l 由上边原因,SpringMVC的方法之间基本上独立的,独享request response数据,请求数据通过参数获取,处理结果通过ModelMap交回给框架,方法之间不共享变量,而Struts2搞的就比较乱,虽然方法之间也是独立的,但其所有Action变量是共享的,这不会影响程序运行,却给我们编码 读程序时带来麻烦,每次来了请求就创建一个Action,一个Action对象对应一个request上下文。
l 由于Struts2需要针对每个request进行封装,把request,session等servlet生命周期的变量封装成一个一个Map,供给每个Action使用,并保证线程安全,所以在原则上,是比较耗费内存的。
l 拦截器实现机制上,Struts2有以自己的interceptor机制,SpringMVC用的是独立的AOP方式,这样导致Struts2的配置文件量还是比SpringMVC大。
l SpringMVC的入口是servlet,而Struts2是filter(这里要指出,filter和servlet是不同的。以前认为filter是servlet的一种特殊),这就导致了二者的机制不同,这里就牵涉到servlet和filter的区别了。
l SpringMVC集成了Ajax,使用非常方便,只需一个注解@ResponseBody就可以实现,然后直接返回响应文本即可,而Struts2拦截器集成了Ajax,在Action中处理时一般必须安装插件或者自己写代码集成进去,使用起来也相对不方便。
l SpringMVC验证支持JSR303,处理起来相对更加灵活方便,而Struts2验证比较繁琐,感觉太烦乱。
l Spring MVC和Spring是无缝的。从这个项目的管理和安全上也比Struts2高(当然Struts2也可以通过不同的目录结构和相关配置做到SpringMVC一样的效果,但是需要xml配置的地方不少)。
l 设计思想上,Struts2更加符合OOP的编程思想, SpringMVC就比较谨慎,在servlet上扩展。
l SpringMVC开发效率和性能高于Struts2。
l SpringMVC可以认为已经100%零配置。
69.#和$的区别
#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by "111", 如果传入的值是id,则解析成的sql为order by "id".
l $将传入的数据直接显示生成在sql中。如:order by $user_id$,如果传入的值是111,那么解析成sql时的值为order by user_id, 如果传入的值是id,则解析成的sql为order by id.
l #方式能够很大程度防止sql注入。
l .$方式无法防止Sql注入。
l $方式一般用于传入数据库对象,例如传入表名。
l .一般能用#的就别用$.
70.人民币类型
l M0 M1 M2
M0=流通中现金 M1=M0+非金融性公司的活期存款 M2=M1+非金融性公司的定期存款+储蓄存款+其他存款