java笔记问题总结KING。。。

标记-清除算法是最基本的算法,和他的名字一样,分为两个步骤,一个步骤是标记需要回收的对象。在标记完成后统一回收被标记的对象。这个算法两个问题。一个是效率问题,标记和清除的效率不高。第二个问题是标记-清除之后会有大量不连续的碎片空间,如果我们需要更大的连续内存就必须GC。

复制算法

标记-整理算法

主要特点是,解决了碎片问题。标记整理算法,标记过程和第一算法一样,但是他处理的时候会让存活的对象向一边移动解决了空间碎片问题,用于老年代的处理。

分代收集算法

分代收集算法不是新思想,只是把上面的算法结合起来了。

AtomicInteger使用value来保存值,value是volatile的,保证了可见性。

对于get方法直接返回value,对于自增一或者添加值使用了CAS自旋锁,使用了一个死循环,如果cas返回为true就可以退出循环。对于CAS全称是compareandswap比较和交换,CAS需要三个操作数,一个是变量内存地址,一个是excepted过期值,一个是现在要更新的值,我们操作的时候仅当V符合旧预期的值的时候才能更新我们新的。对于它的自增的操作,首先是卸载一个for循环里面然后获得当前的值,给这个值+1,然后进行cvs要是失败会再次Get()最新值再次写.

用法区别,性能区别,锁机制的区别。

对于用法区别:synchronized可以在方法中上使用也可以在特定代码块中使用,括号中表示需要锁的对象,如果在方法上就是对该对象的锁,如果是在类的方法上就是类的锁,使用Lock必须自己用代码显示申明何时开启锁,何时关闭锁。synchronized是jvm的底层实现,而Lock是由代码执行。

对于性能的区别:ReentrantLock功能上要多于synchronized,多了锁投票,定时锁等。如果在小规模的竞争上synchronized效率比较高,如果在大规模的竞争上synchronize就比较低而Lock基本不变、

锁的机制也不同:synchronized获得锁和释放锁都是在块中,都是自动释放,不会引起死锁,而Lock需要自己定位释放,不然会引起死锁。在Lock中也使用了tryLock方法用非阻塞的方式获取锁。

在lock中用一个锁变量和队列维护同步。

gc停顿原因,如何降低GC停顿

jvm如何调优,参数怎么调?如何利用工具分析jvm状态?

合理的分配内存,分配栈和堆的内存,在堆中我们还可以详细划分新生代和老年代的内存比例,在新生代中我们也可以划分Eden和Surivior的内存比例(调该比例大小),合理的划分内存区域大小,可以帮助我们jvm调优,我们采取合适的垃圾回收器,比如在新生代启用serial垃圾回收器,在老年代采用cms并发标记,可以降低GC停顿,当然也可以尝试去采用G1垃圾回收器

jvm中类加载过程

类加载到类被卸载过程包括7个阶段

1.加载

通过类的全限定名把类文件的二进制流加入进来,通过这个字节流(这个二进制流也是我们代理类的方法),然后通过这个二进制流把静态存储结构转化为运行时方法区的结构(不包括类变量,类变量在准备阶段),在内存中生成一个Class对象,作为方法区访问的入口。

2.验证验证是验证Class文件的字节流包含的信息是否符合当前虚拟机的要求规范,防止恶意攻击、

3.准备在方法区为类变量分配内存和设置初始值,这个时候的初始值是数据的0值,不是我们定义的值,如果是常量的话准备阶段就会设置为我们定义的值

4.解析将符号引用(这里的符号引用指的是字面量的形式,只需要无歧义地定位到目标)替换为直接变量

5.初始化类初始化阶段是我们加载过程的最后一步,执行类构造器,合并static语句,有static的顺序决定。

6.使用

7.卸载

Ioc—InversionofControl,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。

spring中Bean的加载机制其实就是IOC容器的初始化,比如我们这里定义了一个IOC容器,BeanFactroy的子类ClassXMLPathApplicationContext,在他的构造函数中我们会把xml路径写进去这个步骤就是定位,接下来就是BeanDefiniton的载入,在构造函数当中有一个refresh()的函数,这个就是载入BeanDefinition的接口,这个方法进去之后是一个同步代码代码块,把之前的容器销毁和关闭创建了一个BeanFatroy,就像对我们的容器重新启动一样,然后我们对BeanDefiniton载入和解析解析完毕之后会把beanDefinition和beanName放入BeanFactory的HashMap中维护。在这里Bean已经被创建完成,然后我们就像IOC容器索要Bean,如果是第一次索要会触发依赖注入,会递归的调用gebBean实现依赖出入.

而对于ReentrantLock是代码上的实现

进程是一段正在执行的程序,线程也叫作”轻量级进程“,他是程序执行的最小单元,一个进程可以有多个线程,各个线程之间共享程序的内存空间(比如说堆空间)及一些进程级的资源,进程和进程之间不能共享内存只能共享磁盘文件,线程也有4中状态:就绪,运行,挂起,死亡。

(新版本)进程是程序执行时的一个实例,从内核的观点看,进程的目的就是担当分配系统资源的基本单位。

线程是进程的一个执行流,是cpu调度和分配的基本单位,它是比进程更小的能独立运行的基本单位。一个进程由几个线程组成,线程和同属一个进程的其他的线程共享进程所拥有的全部资源。

进程-资源分配的最小单位。线程-程序执行的最小单位。

进程由独立的空间地址,线程没有单独的地址空间同一进程内的共享进程的地址空间,只有自己独立的堆栈和局部变量。对于我们来说实现一个多线程的任务比实现一个多进程的任务好,

(1)地址空间:进程内的一个执行单元;进程至少有一个线程;它们共享进程的地址空间;而进程有自己独立的地址空间;

(2)资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源

(3)线程是处理器调度的基本单位,但进程不是.

首先简单说一下SpringAOP几个比较重要的名词:

通知:定义在连接点做什么,为切面增强提供织入接口,意思就是说增强的内容以及增强的方式

切点:PointCut:决定通知应用于什么方法上或者类上。(点:方法或者类)

通知器:连接切点和通知结合起来,可以让我们知道那个通知应用于哪个结点之上,这个结合为应用使用Ioc容器配置AoP应用

开始我们使用AOP的时候是用得java编写的切面通知使用XML配置,后面我们摒弃了采用@AspectJ注解对其进行标注

然后AOP的实现原理有一个ProxyFactoryBean(代理工厂),这个ProxyFactoryBea是在SpringIoc环境之中,创建AOP应用的最底层。在ProxyFactoryBean中我们会配置好通知器Advisor,在ProxyFactory需要为目标对象生成代理对象。ProxyFactory有一个getObject方法,在我们IOC容器中如果获取这个bean会自动调用这个方法,首先第一步初始化通知器链,通知器链只会初始化一次,使用标志位判断,遍历通知器,把所有通知器加入拦截器链,接下来就是代理对象的生成,利用目标对象以及拦截器我们可以正确的生成代理对象,这里生成代理对象有两种方法一种是jdk一种是cglib,在得到AopProxy代理对象之后,我们首先会根据配置来对拦截器是否与当前的调用方法想匹配,如果当前方法匹配就会发挥作用,他会遍历Proxy代理对象中设置拦截器链的所有拦截器,拦截器调用完成之后才是目标对象的调用,这个时候会有一个注册机制,在拦截器中运行的拦截器,会注册,我们就不需要再判断。Aop的源代码中也大量使用了IOC容器,比如从IOC中找到通知器。

详细版本:

实现runnable接口重写run方法,继承Thread,利用线程池来创建。

CountDownLatch:CountDownLatch首先我们在构造函数当中传入了一个标志值,然后在需要阻塞的地方调用await(),直到其他线程把countDown减少完。这个是不可重用的。

CyclicBarrier:和他的名字一样栅栏,我们对他的构造函数传入一个栅栏值,在需要阻塞的地方调用await的时候我们就对其基础值加一,直到等于栅栏值。调用CylicBarrier的reset方法可以对他进行重置。

Semaphore信号量:Semaphore可以同时控制访问的线程个数,如果需要这个资源我们会acquire()以阻塞的方式去请求,如果没有可用的信号量,就等待,release释放信号量,这个机制有点类似于锁。

在jdk1.7中提供了一个同步器Phaser,作用和countdownLatch,CyclicBarrier类似,但PHaser的使用方式更为灵活。使用register注册方法递增计数器,使用arriveAndDeregister()方法来递减计数器,使用arriveAndAwaitAdvane()方法阻塞线程,当计数器归0唤醒。

第一:volatile是Java虚拟机提供的最轻量级的同步机制,使变量对所有的线程可见,保证了可见性,但是并不能保证它的原子性。

第二个:禁止指令重排序优化。普通变量仅仅保证在该方法所有依赖赋值结果的地方都能获取到正确的结果,而不能保证变量赋值操作的顺序与程序代码中的执行一样。从硬件的方面来说,并不是指令任意重拍,他只是把多条指令不安程序规定顺序分发给电路处理单元,比如说2*3+52*3之间是有依赖,5就可以排到他们前面。volatile会帮助我们加入内存屏障防止重排序。volatile读操作性能消耗与普通变量几乎没区别,写操作会慢一些,因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行。

注意:对于volatile修饰的变量,jvm只是保证从主内存加载到线程的工作的内存是最新的

(1)java虚拟机规范试图定义一种JAVA内存模型来屏蔽掉各种硬件和操作系统的内存访问的差异。

(2)java内存模型的主要目标是定义程序中各个变量的访问规则,这里的变量不包含局部变量和方法参数,而是指的是实例字段、静态字段、和构成数组对象的元素。

(3)java内存模型规定了所有的变量都存储在主内存中,而线程内的局部变量在自己的工作内存中,并且还有被该线程使用到的变量的主内存的副本拷贝,线程对变量的操作(读取、赋值)都在工作内存中进行,不能直接读写主内存的变量,不同的线程无法直接访问对方工作内存的变量,线程键的变量值的传递需要通过主内存来完成,在内存模型中比较重要的就是工作线程和主内存的交互。

内存之间的交互:

java内存模型定义的操作:

Lock(锁定)

Unlock(解锁)

Read(读取)

Load(载入)

Use(使用)

Assign(赋值)

Store(存储)

Write(写入)

变量从主内存到工作内存:按照顺序执行readload操作

变量从工作内存到主内存:按照顺序执行Storewrite操作

重排序:

包括:编译器优化重排序、指令级并行重排序、内存系统重排序

首先分写LinkedList和ArrayList的不同,在经常插入和删除的时候,在实现栈和队列的时候,不适合随机查找元素。

wait,notify,notifyall,clone,getclass,toString,equals,hashcode,finalize。

1、Clone()方法

private保护方法,实现对象的浅复制,只有类实现了Clonable接口才可以调用该方法,否则抛出CloneNotSupportException。clone是浅复制,复制完成后其中的变量引用还是和以前的一样,如果要实现深复制需要我们把所有的变量引用都递归复制一次,然后再赋值。(或者额使用序列化,也可以实现深拷贝)如果我们要自己实现clone()方法必须要实现克隆接口clonable。

2、Equals()方法

在object中与==是一样的,子类一般需要重写该方法

3、hashCode()方法

该方法用于哈希查找,重写了equals方法一般都要重写hashcode方法,这个方法在一些具有哈希功能的collection中使用

4、getClass()方法

final方法,获得运行时的类型

5、Wait()方法

6、Notify()方法

唤醒在该对象上的等待的某个线程

7、notifyAll()方法

唤醒在该对象上的等待到所有的线程

8、toString()方法

把对象转换成string类型进行输出

9、finalize()方法

finalize在我们垃圾回收器回收这个对象的时候工作,可以做一些后续的工作,即进行一些必要的清理和清除的工作,比如说关闭流。当然我们也可以在这个里面对我们即将被回收的对象逃出回收。这里需要注意的是系统只会调用一次finalize()方法。但是一般我们不推荐使用这个方法,因为这个方法是为了对开始C和C++程序员的一种妥协,因为C中有析构函数,这个方法运行代价高,不确定大,我们还是会推荐使用try{}finally,他做的方法try{}finally都可以做。

使用线程池来管理线程

在Java中实现多种线程池

我们使用executors工厂产生我们的线程池,当线程池达到负载的时候会在我们线程池管理的Runnable阻塞队列中等待,不会像线程那样竞争CPU

第一种newFixedThreadPool,和它的名字一样这是一个固定线程池,我们可以设置基本大小也就是我们没有任何任务执行的时候的大小,最大大小,只有在工作队列满了才能达到最大大小。

第二种newCachedThreadPool这种线程池把大小设置为Integer.MAX_VALUE,基本大小设置为0,空闲超时设置1分钟,这种线程池可以无限扩展,并且当需求降低时会自动收缩。

第三种newSingleThreadPool这种线程池把基本大小设置为1,最大大小都设置为1,只允许同一时刻一个线程。

固定线程池和单线程池固定默认使用的是阻塞队列无界的LinkedBlockingQueue,在这个阻塞队列中可以无限增长。但是对于我们的newCachedThreadPool来说他的线程池是无限大的,不需要阻塞等待,我们这里使用的是SynchronousQueue来避免排队,其实这个东西不是一个队列,是直接在线程之间进行移交,当线程池的大小小于所需要的时候,要么创建一个要么拒绝一个。我们一般在使用的时候可以扩展,使用使用信号量来控制提交速率。

1.使用join方法可以等待A线程结束,或者单线程池中阻塞队列的方式让A先获得单线程池的线程,然后B一直阻塞,知道A释放自己的线程。

,首先设置堆的大小,一般设置xmx和xms大小相同,如果老年代容易溢出可以扩充老年代,也要适当的调整永久代大小,选择自己合适的收集器,调整新生代对象年龄阀值等。

线程会分为两种:

普通线程和守护线程。在JVM启动时创建的所有线程中,除了主线程其他都是守护线程,比如说垃圾回收器就是守护线程,当普通线程全部退出的时候守护线程也会退出,我们自己也可以手动设置手动线程在线程启动之前,但是我们应该尽可能少使用守护线程,因为我们很少有操作可以在不进行清理就可以安全地抛弃,比如说I/O操作。

拥塞控制就是防止过多的数据注入网络中,这样可以使网络中的路由器或链路不致过载。

发送方维持一个叫做拥塞窗口cwnd(congestionwindow)的状态变量。

为了防止cwnd增长过大引起网络拥塞,还需设置一个慢开始门限ssthresh状态变量。ssthresh的用法如下:

当cwnd时,使用慢开始算法。也就是乘法算法

当cwnd>ssthresh时,改用拥塞避免算法。也就是加法算法

当cwnd=ssthresh时,慢开始与拥塞避免算法任意。

当出现拥塞的时候就把心的门限值设为此时窗口大小的一般,窗口大小设置为1,再重新执行上面的步骤。

当收到连续三个重传的时候这就需要快重传和快恢复了,当收到连续三个重传这个时候发送方就要重传自己的信息,然后门限减半但是这个时候并不是网络阻塞,窗口只会减半执行拥塞避免算法。

我们使用ThreadLocal为每个使用该类型的变量提供了一个独立的副本,具体的实现是在每个线程中保存了一个ThreadLocalMap,这个ThreadLoaclMap会在我们第一次使用ThreadLoal中的set方法创建出来,set方法就是保存在ThreadLocalMap中,该变量为key,值为value,get方法也从这个HashMap中找。

网卡在哪一层(物理层)

交换机在哪一层(链路层)

路由器在哪一层(网络层)

传输TCP

会话SQL

表示IMG

html在应用层

1.0默认是多次tcp连接多次请求,然后增加了keepalive功能,但是必须在requestHeader手动增加Connection:keepalive

1.1是一次tcp连接多次请求,新的persistence功能

长的说:

而对于POST,浏览器先发送header,服务器响应100continue,浏览器再发送data,服务器响应200ok(返回数据)。

也就是说,GET只需要汽车跑一趟就把货送到了,而POST得跑两趟,第一趟,先去和服务器打个招呼“嗨,我等下要送一批货来,你们打开门迎接我”,然后再回头把货送过去。

1.GET与POST都有自己的语义,不能随便混用。

3.并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。

1.get是从服务器上获取数据,post是向服务器传送数据。

2.get是通过URL来传递数据,POST是通过表单传递,因此get数据限制在1024k,而POST没有限制

3.在java服务器端get是通过request.qureyStingpost通过request.getParameterNames和reque.getParameterValue

4.get是安全的,幂等的POST即不安全又不幂等(多次操作和一次操作一样)

在rest中设计的话,一般get用来查询数据,POST用来添加数据,PUT用来更新数据,Delete用来删除数据

多个filter的执行顺序是web.xml中的配置顺序

影响SQL执行效率的因素?

1.isnull和isnotnull

2.通配符的like

3.orderby

4.not

5.in和exists

GBK和UTF-8的区别

GBK包含全部中文字符;UTF-8则包含全世界所有国家需要用到的字符。

GBK的文字编码是双字节来表示的,即不论中、英文字符均使用双字节来表示,只不过为区分中文,将其最高位都定成1。

至于UTF-8编码则是用以解决国际上字符的一种多字节编码,它对英文使用8位(即一个字节),中文使用24位(三个字节)来编码。对于英文字符较多的论坛则用UTF-8节省空间。

UTF8是国际编码,它的通用性比较好,外国人也可以浏览论坛GBK是国家编码,通用性比UTF8差,不过UTF8占用的数据库比GBK大~

1.三者在执行速度方面的比较:StringBuilder>StringBuffer>String

看servlet和Filter的实现原理

StringBuffer是线程安全的,St不是线程安全的,内部的实现是使用char数

一次网站访问的全过程:

二、应用层应用HTTP协议发送数据

三、数据到达传输层封装成数据段,主机使用1024以后的随机源端口号,目标端口号为80

四、数据段到达网络层封装成数据包,加入主机源IP地址和目标IP地址

调用wait()/notify()/notifyAll()中的任何一个方法时,如果当前线程没有获得该对象的锁,

那么就会抛出IllegalMonitorStateException的异常

也就是说程序在没有执行对象的任何同步块或者同步方法时,

仍然尝试调用wait()/notify()/notifyAll()时。由于该异常是RuntimeExcpetion的子类,

所以该异常不一定要捕获(尽管你可以捕获只要你愿意

作为RuntimeException,此类异常不会在wait(),notify(),notifyAll()的方法签名提及。

返回了一个同步容器,在这个同步容器中的所有方法都有一个锁为当前对象或者指定锁的同步块,用这种阻塞同步的方法可以让我们容器同步

Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。

1.cancel方法用来取消任务

2.isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回true。

3.isDone()表示是否完成

4.get()获得执行结果,这个方法会一直阻塞

FutureTask是Future的实现类

J2EE服务器启动时会建立一定数量的池连接,并一直维持不少于此数目的池连接。

调用:客户端程序需要连接时,池驱动程序会返回一个未使用的池连接并将其表记为忙。如果当前没有空闲连接,池驱动程序就新建一定数量的连接,新建连接的数量有配置参数决定。

释放:当使用的池连接调用完成后,池驱动程序将此连接表记为空闲,其他调用就可以使用这个连接。

数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。

数据库连接池的最小连接数和最大连接数的设置要考虑到下列几个因素:

1)最小连接数是连接池一直保持的数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费;

2)最大连接数是连接池能申请的最大连接数,如果数据库连接请求超过此数,后面的数据库连接请求将被加入到等待队列中,这会影响之后的数据库操作。

3)如果最小连接数与最大连接数相差太大,那么最先的连接请求将会获利,之后超过最小连接数量的连接请求等价于建立一个新的数据库连接。不过,这些大于最小连接数的数据库连接在使用完不会马上被释放,它将被放到连接池中等待重复使用或是空闲超时后被释放。

存储过程是用户定义的一系列sql语句的集合,涉及特定表或其它对象的任务,用户可以调用存储过程,而函数通常是数据库已定义的方法,它接收参数并返回某种类型的值并且不涉及特定用户表。

事务是作为一个逻辑单元执行的一系列操作。

游标用于定位结果集的行,通过判断全局变量@@FETCH_STATUS可以判断是否到了最后,通常此变量不等于0表示出错或到了最后。

管道(pipe):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。

命名管道(namedpipe):命名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。

信号量(semophore):信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。

消息队列(messagequeue):消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

信号(sinal):信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

共享内存(sharedmemory):共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。

套接字(socket):套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。

溢出解决:

1.在代码中减少不必要的实例构造

2.设置堆和永久代的大小-xms堆最小-xmx堆最大

内存泄露:

内存泄露不能通过配置解决代码的问题。比如资源在使用完毕后没有释放,一些对象存在无效引用我们不能回收。

jps:显示系统内所有进程的信息。

jstat:收集虚拟机各种运行状态信息的命令行工具。-gc,监视java堆-class就是监视类加载,还可以监视编译状况。

jinfo:java配置信息工具。

jmap:用于生成堆转储快照有些选项只能在linux下才能看见。

jhat:配合jmap。

jstack:堆栈追踪。

1.加载:在Servlet容器启动的时候会通过类加载器加载我们的Servlet的Class文件。

2.创建:在创建过程的时候如果没有在web.xml文件中使用load-on-startup我们在第一次访问我们的Servlet的时候会初始化实例,如果配置了这个并且大于1会在容器启动的时候就创建。

3.初始化:init()初始化的方法只会被调用一次。在我们实例化被创建之后就会执行初始化。

5.卸载:destroy()当我们Servlet需要被卸载的时候就会调用我们的destory()方法,随后垃圾回收器会回收。

当我们需要向新生代中分配内存时出现不足的情况:会出现MinorGC,在新生代中都是朝生夕灭的对象,频率比较高。MinorGC发生在新生代。

FULLGC指在老年代发生的GC,一般情况下出现了FULLGC都会伴随着一次MinorGC。

为什么MinorGC和FULLGC速度有差距呢?

在MinorGC中使用的copy算法,在FullGC中使用的是标记清除或者标记整理算法。

但是mark-sweap或mark-compact都是分为两个阶段,先标记再清除是两步骤。

所以MinroGC速度会快于FullGC。

对于JVM调优的重点是垃圾回收和内存管理。

垃圾回收我们可以使用我们的cms垃圾回收器。

对于内存管理有:

永久代溢出、栈溢出、堆溢出的情况

永久代溢出:

针对永久代溢出在JVM默认情况只有64M的永久代大小,很多东西都需要我们永久代区内存,尤其是使用Spring等框架的时候会有cglib的动态字节码生成class,都会存储在我们的永久代。所以我们需要扩充永久代防止内存溢出。

堆溢出:

对于堆溢出我们也是比较常见的比如说我们使用容器的时候没有释放内存很有可能就会导致堆溢出,需要动态扩展。

栈溢出:

对于栈我们也可以设置提高。

(1)恶汉式的单例模式

利用静态static的方式进行实例化,在类被加载时就会创建实例。

/**

*饿汉式实现单例模式

*/

publicclassSingleton{

privatestaticSingletoninstance=newSingleton();//在类加载时实例单例对象

privateSingleton(){//私有的构造器

}

publicstaticSingletongetInstance(){//返回一个实例对象

returninstance;

(2)懒汉式实现单例模式

在被第一次引用时才去创建对象。

*懒汉式实现单例模式

privatestaticSingletoninstance;//创建私有的静态变量

privateSingleton(){//私有的构造函数

//synchronized方法,多线程情况下保证单例对象唯一

publicstaticsynchronizedSingletongetInstance(){

//如果实例对象为空,就重新去实例化

if(instance==null){

instance=newSingleton();

分析:这中方法的实现,效率不高,因为该方法定义为同步的方法。

(3)双重锁实现的单例模式doublecheck

*DCL实现单例模式

privatestaticvalotileSingletoninstance=null;//这里要加入valotile关键字,避免指令重排序,可能先赋值但是没有分配内存

privateSingleton(){

publicstaticSingletongetInstance(){

//两层判空,第一层是为了避免不必要的同步

//第二层是为了在null的情况下创建实例

synchronized(Singleton.class){

分析:资源的利用率较高,在需要的时候去初始化实例,而且可以保证线程的安全,该方法没有去进行同步锁,效率比较好。

(4)静态内部类实现单例模式

*静态内部类实现单例模式

//返回实例的方法

returnSingletonHolder.instance;

*静态内部类

privatestaticclassSingletonHolder{

//静态私有的实例对象

privatestaticSingletoninstance=newSingleton();

分析:第一次加载类时不会去初始化instance,只有第一次调用getInstance()方法时,虚拟机才会加载内部类,初始化instance

可以保证线程的安全,单例对象的唯一,延迟了单例的初始化。

(5)枚举单例

*枚举实现单例模式

publicenumSingletonEnum{

INSTANCE;//直接定义一个实例对象

publicvoiddoSomething(){

System.out.println("dosomething");

分析:枚举实例的创建是线程安全的,即使反序列化也不会生成新的实例,在任何的情况下都是单例的。

1.单一职责。2.里氏替换3.依赖导致4接口隔离5.迪米特法则6.开闭原则。

XML的优点

A.格式统一,符合标准;

B.容易与其他系统进行远程交互,数据共享比较方便。

C.可读性高

XML的缺点

A.XML文件庞大,文件格式复杂,传输占带宽;

B.服务器端和客户端都需要花费大量代码来解析XML,导致服务器端和客户端代码变得异常复杂且不易维护;

C.客户端不同浏览器之间解析XML的方式不一致,需要重复编写很多代码;

JSON的优缺点

JSON的优点:

A.数据格式比较简单,易于读写,格式都是压缩的,占用带宽小;

B.易于解析,客户端JavaScript可以简单的通过eval()进行JSON数据的读取;

C.支持多种语言,包括ActionScript,C,C#,ColdFusion,Java,JavaScript,Perl,PHP,Python,Ruby等服务器端语言,便于服务器端的解析;

D.在PHP世界,已经有PHP-JSON和JSON-PHP出现了,偏于PHP序列化后的程序直接调用,PHP服务器端的对象、数组等能直接生成JSON格式,便于客户端的访问提取;

E.因为JSON格式能直接为服务器端代码使用,大大简化了服务器端和客户端的代码开发量,且完成任务不变,并且易于维护。

JSON的缺点

A.没有XML格式这么推广的深入人心和喜用广泛,没有XML那么通用性;

B.JSON格式目前在WebService中推广还属于初级阶段。

C:可读性低。

1.DOM生成和解析XML文档

为XML文档的已解析版本定义了一组接口。解析器读入整个文档,然后构建一个驻留内存的树结构。

优点:整个文档树在内存中,便于操作;支持删除,修改,重新排列等。

2.SAX为解决DOM

1、边读边解析,应用于大型XML文档

2、只支持读

3、访问效率低

4、顺序访问

3.DOM4J生成和解析XML文档(解析工具)性能最好SUM的JAXM也大量采用DOM4J

HIBERNATE采用DOM4J

虽然DOM4J代表了完全独立的开发结果,但最初,它是JDOM的一种智能分支。它合并了许多超出基本XML文档表示的功能,包括集成的XPath支持、XMLSchema支持以及用于大文档或流化文档的基于事件的处理。它还提供了构建文档表示的选项,它通过DOM4JAPI和标准DOM接口具有并行访问功能。从2000下半年开始,它就一直处于开发之中。

为支持所有这些功能,DOM4J使用接口和抽象基本类方法。DOM4J大量使用了API中的Collections类,但是在许多情况下,它还提供一些替代方法以允许更好的性能或更直接的编码方法。直接好处是,虽然DOM4J付出了更复杂的API的代价,但是它提供了比JDOM大得多的灵活性。

在添加灵活性、XPath集成和对大文档处理的目标时,DOM4J的目标与JDOM是一样的:针对Java开发者的易用性和直观操作。它还致力于成为比JDOM更完整的解决方案,实现在本质上处理所有Java/XML问题的目标。在完成该目标时,它比JDOM更少强调防止不正确的应用程序行为。

DOM4J是一个非常非常优秀的JavaXMLAPI,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件。如今你可以看到越来越多的Java软件都在使用DOM4J来读写XML,特别值得一提的是连Sun的JAXM也在用DOM4J.

4.JDOM

JDOM

优点:①是基于树的处理XML的JavaAPI,把树加载在内存中

②没有向下兼容的限制,因此比DOM简单

③速度快,缺陷少

④具有SAX的JAVA规则

缺点:

①不能处理大于内存的文档

②JDOM表示XML文档逻辑模型。不能保证每个字节真正变换。

③针对实例文档不提供DTD与模式的任何实际模型。

④不支持与DOM中相应遍历包。

最适合于:JDOM具有树的便利,也有SAX的JAVA规则。在需要平衡时使用

有两种办法

1.第一种消毒,通过正则匹配过滤请求数据中可能注入的SQL。

2.使用预编译手段preparedStatemengt。

第一范式:没一列属性不可再分,没有多值属性

第二范式:在符合第一范式的基础上,存在主键

第三范式:在符合第二范式的基础上,非关键字独立于其他的非关键字,并且依赖关键字。不能存在传递依赖。

private:用于修饰类和方法,只允许该类访问。

默认:只允许在同一个类和同一个包中进行访问。

protected:用于修饰类和方法,允许该类和子类访问以及同一个包中访问。

public:用于修饰类和方法,允许该包下面和其他包的访问,即在全局范围都可以访问。

事务的特性:

原子性:事务是不可再分的;

一致性:事务的实行前后,数据库的状态保持一致;

隔离性:事务的并发访问,事务之间的执行互不干扰;

持久性:事务结束后数据永久保存在数据库中。

什么是脏读?

脏读就是一个事务读取了该数据并且对该数据做出了修改,另一个事务也读取了该修改后的数据但是前一个事务并没有提交,这是脏数据。

读取到保存在数据库内存中的数据。

什么是不可重复读?

一个事务:在同一个事务中读取同一数据,得到的内容不同。一个事务读取另外一个事务更新的数据,导致二次的查询的数据不一致。

什么是幻读?

幻读是当事务不独立发生的。比如一个事务删除了所有数据,另一个事务又插入了一条,那么第一个事务的用户会发现表中还没有修改的数据行。一个事务读取到另外一个事务提交的数据,导致查询的结果不一致的问题。

数据库的隔离级别:

Readuncommitted:未提交读:三中都有可能发生

Readcommitted:已提交读避免脏读

Repeatedread:重复读:避免脏读不可重复读

Serializable:串行化读都可以避免

一言以蔽之:WebService是一种跨编程语言和跨操作系统平台的远程调用技术。

所谓跨编程语言和跨操作平台,就是说服务端程序采用java编写,客户端程序则可以采用其他编程语言编写,反之亦然!跨操作系统平台则是指服务端程序和客户端程序可以在不同的操作系统上运行。

所谓远程调用,就是一台计算机a上的一个程序可以调用到另外一台计算机b上的一个对象的方法,譬如,银联提供给商场的pos刷卡系统,商场的POS机转账调用的转账方法的代码其实是跑在银行服务器上。再比如,amazon,天气预报系统,淘宝网,校内网,百度等把自己的系统服务以webservice服务的形式暴露出来,让第三方网站和程序可以调用这些服务功能,这样扩展了自己系统的市场占有率,往大的概念上吹,就是所谓的SOA应用。

其实可以从多个角度来理解WebService,从表面上看,WebService就是一个应用程序向外界暴露出一个能通过Web进行调用的API,也就是说能用编程的方法通过Web来调用这个应用程序。我们把调用这个WebService的应用程序叫做客户端,而把提供这个WebService的应用程序叫做服务端。从深层次看,WebService是建立可互操作的分布式应用程序的新平台,是一个平台,是一套标准。它定义了应用程序如何在Web上实现互操作性,你可以用任何你喜欢的语言,在任何你喜欢的平台上写Webservice,只要我们可以通过Webservice标准对这些服务进行查询和访问。

WebService平台需要一套协议来实现分布式应用程序的创建。任何平台都有它的数据表示方法和类型系统。要实现互操作性,WebService平台必须提供一套标准的类型系统,用于沟通不同平台、编程语言和组件模型中的不同类型系统。Webservice平台必须提供一种标准来描述Webservice,让客户可以得到足够的信息来调用这个Webservice。最后,我们还必须有一种方法来对这个Webservice进行远程调用,这种方法实际是一种远程过程调用协议(RPC)。为了达到互操作性,这种RPC协议还必须与平台和编程语言无关。

2.减少锁的粒度,合适的锁的代码块,可以减少竞争,控制锁的范围。

3.锁分离,将锁安功能划分,比如读写锁,读读不互斥,读写互斥,写写互斥,保证了线程的安全,提高了性能。比如阻塞队列中的take和put

4.锁粗化,如果对同一个锁不停的进行请求,同步和释放,这个消耗是非常的大的,所以适当的时候可以粗化。

5.锁消除,编译器可以帮助我们优化比如一些代码根本不需要锁。

1.偏向锁:偏向当前已经占有锁的线程,在无竞争的时候,之前获得锁的线程再次获得锁时,会判断是否偏向锁指向我,那么该线程将不用再次获得锁,直接进入同步块。

2.轻量级锁:偏向锁失败后,利用cas补救补救失败就会升级为重量级锁。

3.自旋锁:会做空操作,并且不停地尝试拿到这个锁。

先利用Hash法去重复,去除大量的之后然后等量的分成100份用小顶堆来获得10000个,再把所有的1万个都合在一起就OK

java中的线程的状态有5种(新建、就绪、运行、阻塞、结束)

1.新建:创建后尚未启动的线程处于这种状态,新建出一个线程对象。

2.就绪状态:当针对该对象掉用了start()方法,该线程等待获取CPU的使用权

3.运行状态:在就绪状态下,获得了CPU处于运行状态。

4.阻塞:

等待阻塞:运行的线程执行wait方法,JVM会把该线程放入等待池

同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被其他的线程锁占用,则jvm会把该线程放入锁池中。

其他阻塞:运行的线程在执行sleep()方法或者join()方法时,或者发出IO请求,JVM会把线程置为阻塞状态。

5.结束:

也就是我们的死亡,表明线程结束。

maven有三套相互独立的生命周期

1.clean生命周期

pre-clean,clean,post-clean

2.default生命周期构建项目

1.validate:验证工程是否正确,所有需要的资源是否可用

2.compile:编译项目源代码

3.test:使用合适的单元框架来测试已编译的源代码。

4.Package:把已编译的代码打包成可发布的格式,jar。

4)Package:把已编译的代码打包成可发布的格式,比如jar。

5)integration-test:如有需要,将包处理和发布到一个能够进行集成测试的环境。

6)verify:运行所有检查,验证包是否有效且达到质量标准。

7)install:把包安装到maven本地仓库,可以被其他工程作为依赖来使用。

8)Deploy:在集成或者发布环境下执行,将最终版本的包拷贝到远程的repository,使得其他的开发者或者工程可以共享。

3.

site生命周期:建立和发布项目站点,phase如下

1)pre-site:生成项目站点之前需要完成的工作

2)site:生成项目站点文档

3)post-site:生成项目站点之后需要完成的工作

4)site-deploy:将项目站点发布到服务器

数据库索引

(1)索引是对记录集多个字段进行排序的方法。

弊端:建立索引表也是会需要额外的空间。

在对表中记录进行搜索时并不是对表中的数据进行全部的扫描遍历,而是查看在索引中定义的有序列,一旦在索引中找到了要查询的记录,就会得到一个指针,它会指向相应的表中数据所保存的位置。

(1)聚集索引:数据页在物理上的有序的存储,数据页的物理顺序是按照聚集索引的顺序进行排列。在聚集索引中数据页聚集索引的叶子节点,数据页之间通过双向的链表形式相连接,实际的数据存储在叶节点中。

(2)非聚集索引:叶子节点不存放具体的数据页信息,只存放索引的键值。非聚集索引的叶子节点包含着指向具体数据的指针,数据页之间没有连接,是相对独立的。

(3)唯一索引:在整个表中仅仅会出现一次(主键约束/UNIQUE)

(4)非唯一索引:在提取数据时允许出现重复的值。

(5)单一索引和组合索引

1.条件中有or但是前后没有同时使用索引

2.多列索引,不是使用前面部分

3.like查询是以%开头

4.字符类型应该加单引号防止转换为int类型

1、应尽量避免在where子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。

2、对查询进行优化,应尽量避免全表扫描,首先应考虑在where及orderby涉及的列上建立索引。

3、应尽量避免在where子句中对字段进行null值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:

selectidfromtwherenumisnull

可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:

selectidfromtwherenum=0

4、尽量避免在where子句中使用or来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:

selectidfromtwherenum=10ornum=20

可以这样查询:

selectidfromtwherenum=10

unionall

selectidfromtwherenum=20

5、下面的查询也将导致全表扫描:(不能前置百分号)

selectidfromtwherenamelike‘c%’

若要提高效率,可以考虑全文检索。

6、in和notin也要慎用,否则会导致全表扫描,如:

selectidfromtwherenumin(1,2,3)

对于连续的数值,能用between就不要用in了:

selectidfromtwherenumbetween1and3

7、如果在where子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:

selectidfromtwherenum=@num

可以改为强制查询使用索引:

selectidfromtwith(index(索引名))wherenum=@num

8、应尽量避免在where子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:

selectidfromtwherenum/2=100

应改为:

selectidfromtwherenum=100*2

9、应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:

selectidfromtwheresubstring(name,1,3)=’abc’–name以abc开头的id

selectidfromtwheredatediff(day,createdate,’2005-11-30′)=0–’2005-11-30′生成的id

selectidfromtwherenamelike‘abc%’

selectidfromtwherecreatedate>=’2005-11-30′andcreatedate<’2005-12-1′

10、不要在where子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。

11、在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。

12、不要写一些没有意义的查询,如需要生成一个空表结构:

selectcol1,col2into#tfromtwhere1=0

这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:

createtable#t(…)

13、很多时候用exists代替in是一个好的选择:

selectnumfromawherenumin(selectnumfromb)

用下面的语句替换:

selectnumfromawhereexists(select1frombwherenum=a.num)

14、并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。

15、索引并不是越多越好,索引固然可以提高相应的select的效率,但同时也降低了insert及update的效率,因为insert或update时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。

16.应尽可能的避免更新clustered索引数据列,因为clustered索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新clustered索引数据列,那么需要考虑是否应将该索引建为clustered索引。

17、尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

18、尽可能的使用varchar/nvarchar代替char/nchar,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

19、任何地方都不要使用select*fromt,用具体的字段列表代替“*”,不要返回用不到的任何字段。

20、尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。

21、避免频繁创建和删除临时表,以减少系统表资源的消耗。

22、临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。

23、在新建临时表时,如果一次性插入数据量很大,那么可以使用selectinto代替createtable,避免造成大量log,以提高速度;如果数据量不大,为了缓和系统表的资源,应先createtable,然后insert。

25、尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。

26、使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。

27、与临时表一样,游标并不是不可使用。对小型数据集使用FAST_FORWARD游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。在结果集中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时间允许,基于游标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。

28、在所有的存储过程和触发器的开始处设置SETNOCOUNTON,在结束时设置SETNOCOUNTOFF。无需在执行存储过程和触发器的每个语句后向客户端发送DONE_IN_PROC消息。

29、尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。

30、尽量避免大事务操作,提高系统并发能力。查询sql语句中哪些比较慢

1.慢查询日志,一般设置查询超过两秒就记录

2.processlist:显示哪些线程正在运行.

3.explain关键字可以让我们更好的优化

1.反范式设计,尽量是单表,可以高效利用索引

2.可以使用查询缓存,Mysql也会自带查询缓存

3.尽量查询通过搜索引擎查不通过我们

4.key,value数据库

1.读写分离,锁分离

3.以正确的顺序获得和释放锁

4.适当的锁的范围扩大或者缩小,控制锁的粒度

singleton:单例模式,在整个SpringIoC容器中,使用singleton定义的Bean将只有一个实例。

prototype:原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例。

request:对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效。

session:对于每次HTTPSession,使用session定义的Bean都将产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效。

Globalsession:每个全局的HTTPSession,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portletcontext的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效。

1.利用sleep特性//休眠

2.time和timerTask//定时器

3.ScheduledExecutorServiceservice.scheduleAtFixedRate(runnable,10,1,TimeUnit.SECONDS);

//任务调度服务

用户程序的地址空间被划分成若干固定大小的区域,称为“页”,相应地,内存空间分成若干个物理块,页和块的大小相等。可将用户程序的任一页放在内存的任一块中,实现了离散分配。

1,SCHED_OTHER分时调度策略,

2,SCHED_FIFO实时调度策略,先到先服务

74.TCP通过什么方式提供可靠性:

1.超时重发,发出报文段要是没有收到及时的确认,会重发。

2.数据包的校验,也就是校验首部数据和。

3.对失序的数据重新排序

4.进行流量控制,防止缓冲区溢出

5.快重传和快恢复

6.TCP会将数据截断为合理的长度

1.UDP是无连接的,TCP必须三次握手建立连接

2.UDP是面向报文,没有拥塞控制,所以速度快,适合多媒体通信要求,比如及时聊天,支持一对一,一队多。多对一,多对多。

3.TCP只能是一对一的可靠性传输

TCP的RPC,在协议栈的下层,能够灵活的对字段进行定制,减少网络传输字节数,降低网络开销,提高性能,实现更大的吞吐量和并发数。但是实现代价高,底层复杂,难以得到开源社区的支持,难以实现跨平台

76.集群调优

1.load

2.CPU利用率

查看cpu的消耗的情况命令:top|grepCpu

查看磁盘的剩余空间命令:df-h

查看系统的内存的使用情况:free-m

1.使用ping命令

对于fullgc导致不响应,网络攻击这种ping展示不明确

2.使用curl

访问我们的自测地址

3.对不同的功能使用curl检测,在response中加入状态头,表示正常

可以计算qps通过28原则

innodb存储引擎通过预写事务日志的方式保障事务的原子性,也就是在写入数据之前,先将数据操作写入日志,这种成为预写日志

轻量级锁认为在程序运行过程中,绝大部分的锁,在整个同步周期内都是不存在竞争的,利用cas操作避免互斥开销。

偏向锁是jdk1.6中引入的一项优化,甚至可以省掉CAS操作,偏向锁偏向第一个获得他锁的线程,如果在接下来执行过程中,这个锁没有被其他线程获取,则持有偏向锁的线程永远不需要同步。

查看GC日志,根据GC日志来优化

我们可以通过jps找到我们虚拟机正在运行的进程。参数通过jps-help了解。

Jstat-gc或者-gcutil查看堆使用情况-class配合Jps得到进程

BTrace原理利用hotspot虚拟中的热替换,把代码动态的替换到java程序内,可在不需要重启的时候就可以排除问题

JConsole

我们也可以使用JConsole来分析这是一个图形化的,比较容易让我们操作

使用VisualVM进行远程连接使用JMX方式,也有修改tomcat的catalina就行了

题目有点问题,并不是所有的外部变量才加final,我们的内部类访问我们的成员变量就不需要加final,但是访问局部变量就必须要加final,因为方法(main方法)结束我们栈帧也就销毁了,但是我们内部类在堆中并没有被销毁,如果引用了成员变量,这时候被销毁了肯定是不行的,所以我们就需要成员变量设置为final,让其在方法(main方法)结束时不会被销毁。

泛型的作用:在我们没有泛型的时候,我们通过对Object的引用来对参数的任意化,任意化有个缺点就是要做显示的强制类型转换,强制转换有一个不好的地方是运行的时候才会报错,泛型的好处实在编译的时候检查类型安全,所以泛型的特点就是简单安全,泛型的原理是类型擦除,java的泛型是伪泛型,在编译期间,所有的泛型信息都会被擦除掉。在生成的java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会在编译器编译的时候去掉。比如List

1.nginx相对于apache来说

(1)轻量级占用的内存少;

(2)抗并发,nginx是异步非阻塞,apache是阻塞的,在高并发的情况下,nginx的性能优;

(3)高度模块化的设计,编写模块相对简单;

(4)社区活跃,各种高性能模块有。

适合场景:apache适合于动态的请求,而负载均衡和静态请求适合nginx,nginx采用的是epoll,并且有自己的一套sendfile系统,减少在内存中的赋值次数。

2.apache相对于nginx的优点:

(1)rewrite,比nginx的rewrite强大;

(2)模块超多,基本想到的都可以找到;

(3)少bug,nginx的bug相对较多;

(4)超稳定。

共享的部分:

1.进程代码段

2.进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯)

3.进程打开的文件描述符、

4.信号的处理器、

5.进程的当前目录

6.进程用户ID与进程组ID

线程独有的内容包括:

1.线程ID

2.寄存器组的值

3.线程的堆栈

4.错误返回码

5.线程的信号屏蔽码

最大的优势就是线程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,线程的性能优势就越明显。

第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在线程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

1.作为高性能的web服务器:相比Apache,Nginx使用更少的资源,支持更多的并发连接,体现更高的效率,这点让Nginx受到虚拟主机提供商的欢迎。一个Nginx实例能够轻松支持高达5万并发。

2.作为负载均衡服务器:Nginx即可以在内部直接支持PHP,也可以支持作为HTTP代理服务器对外进行服务,独有的sendfiles系统,减少文件复制次数。

3.作为邮件代理服务器:也比Apache好很多。

4.Nginx安装简单,配置文件非常简洁。启动容易,7*24小时几乎不间断,可以进行热更新。

(1)提供了高速,面向块的I/O。

(2)在NIO中所有数据都是用缓冲区来处理的,也就是使用我们的jvm中的directmemory(直接内存)。缓冲区是一个数组,但是缓冲区不仅仅是一个数组,缓冲区提供了对数据的结构化访问以及维护读写位置等信息。

(3)在NIO中channel(通道)也是特别重要的他是我们数据读写的通道,一般来说流比如inputStream和outputStream都是单向的,而通道是双向的,是全双工的。

(4)多路复用器Selector也是比较重要的,掌握它对于我们的NIO编程来说是比较重要的。多路复用器提供选择已经就绪的任务的能力。Selector会不断轮训注册在其上的Channel,如果某个Channel上面发生读或者写事件,这个Channel就处于就绪状态,会被Selector轮询出来,通过SelectionKey可以获取就绪Channel的集合,进行后续的I/o操作。我们只需要一个线程就可以管理我们多个客户端。

1.Serial收集器

Serial收集器是JAVA虚拟机中最基本、历史最悠久的收集器,在JDK1.3.1之前是JAVA虚拟机新生代收集的唯一选择。Serial收集器是一个单线程的收集器,但它的“单线程”的意义并不仅仅是说明它只会使用一个CPU或一条收集线程去完成垃圾收集工作,更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。

2.Parallel(并行)收集器

3.CMS收集器

CMS(ConcurrentMarkSweep)收集器是基于“标记-清除”算法实现的,它使用多线程的算法去扫描堆(标记)并对发现的未使用的对象进行回收(清除)。整个过程分为6个步骤,包括:

初始标记(CMSinitialmark)

并发标记(CMSconcurrentmark)

并发预清理(CMS-concurrent-preclean)

重新标记(CMSremark)

并发清除(CMSconcurrentsweep)

并发重置(CMS-concurrent-reset)

trycatch有return在字节码中可以看到会出现Goto跳转行数,跳转到finally中的return

最外层的Server提供接口访问内部的Service服务。

Service服务的作用就是把Connector在Connetor中监听端口和Container连接起来,方便我们的操纵控制。

在tomcat中生命周期是统一的由Lifecycle来管理的

在lifecycle中有两个方法比较重要start和stop,调用server的start会去调用自己下面所有service的start方法

Connector最重要的功能就是接受连接请求然后分配线程处理

在Container中有4个级别Engine,Host,Context,warpper,这四个组件不是平行的,而是父子关系,Engine包含Host,Host包含Context,Context包含Wrapper。通常一个Servletclass对应一个Wrapper,如果有多个Servlet就可以定义多个Wrapper,如果有多个Wrapper就要定义一个更高的Container了,如Context。在Host中有个value比较重要,类似于一个管道,和拦截器链差不多,我们在中间可以进行一些处理。

在Engine中只能添加子容器Host,不能添加父容器.Engine下可以配置多个虚拟主机VirtualHost,每个虚拟主机都有一个域名

当Engine获得一个请求时,它把该请求匹配到某个Host上,然后把该请求交给该Host来处理Engine有一个默认虚拟主机,当请求无法匹配到任何一个Host上的时候,将交给该默认Host来处理

一个Host就类似于一个虚拟主机,用来管理应用。代表一个VirtualHost,虚拟主机,每个虚拟主机和某个网络域名DomainName相匹配

每个虚拟主机下都可以部署(deploy)一个或者多个WebApp,每个WebApp对应于一个Context,有一个Contextpath

当Host获得一个请求时,将把该请求匹配到某个Context上,然后把该请求交给该Context来处理

匹配的方法是“最长匹配”,所以一个path==""的Context将成为该Host的默认Context

所有无法和其它Context的路径名匹配的请求都将最终和该默认Context匹配。

Context代表Servlet的Context,它具备了Servlet运行的基本环境,理论上只要有Context就能运行Servlet了。简单的Tomcat可以没有Engine和Host。

Context最重要的功能就是管理它里面的Servlet实例,Servlet实例在Context中是以Wrapper出现的,还有一点就是Context如何才能找到正确的Servlet来执行它呢?

一个Context对应于一个WebApplication,一个WebApplication由一个或者多个Servlet组成

Context在创建的时候将根据配置文件"role="presentation"style='font-size:14px;font-style:normal;font-weight:normal;color:rgb(0,0,0);'>CATALINAHOME/conf/web.xml和WEBAPP_HOME/WEB-INF/web.xml载入Servlet类

当Context获得请求时,将在自己的映射表(mappingtable)中寻找相匹配的Servlet类

如果找到,则执行该类,获得请求的回应,并返回.

JDK1.5中引入了强大的concurrent包,其中最常用的莫过了线程池的实现。ThreadPoolExecutor(线程池执行器),它给我们带来了极大的方便,但同时,对于该线程池不恰当的设置也可能使其效率并不能达到预期的效果,甚至仅相当于或低于单线程的效率。

ThreadPoolExecutor类可设置的参数主要有:

(1)corePoolSize基本大小

核心线程数,核心线程会一直存活,即使没有任务需要处理。当线程数小于核心线程数时,即使现有的线程空闲,线程池也会优先创建新线程来处理任务,而不是直接交给现有的线程处理。

核心线程在allowCoreThreadTimeout被设置为true时会超时退出,默认情况下不会退出。

(2)maxPoolSize最大大小

当线程数大于或等于核心线程corePoolSize,且任务队列已满时,线程池会创建新的线程,直到线程数量达到maxPoolSize。如果线程数已等于maxPoolSize,且任务队列已满,则已超出线程池的处理能力,线程池会拒绝处理任务而抛出异常。

keepAliveTime大于coolPoolSize的会退出

allowCoreThreadTimeout是否退出核心线程

是否允许核心线程空闲退出,默认值为false。

queueCapacity

任务队列容量。从maxPoolSize的描述上可以看出,任务队列的容量会影响到线程的变化,因此任务队列的长度也需要恰当的设置。

当线程数小于核心线程数时,创建线程。

当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。

当线程数大于等于核心线程数,且任务队列已满

若线程数小于最大线程数,创建线程

若线程数等于最大线程数,抛出异常,拒绝任务

系统负载

tasks,每秒需要处理的最大任务数量

参数设置

corePoolSize:

每个任务需要tasktime秒处理,则每个线程每钞可处理1/tasktime个任务。系统每秒有tasks个任务需要处理,则需要的线程数为:tasks/(1/tasktime),即tasks*tasktime个线程数。假设系统每秒任务数为100~1000,每个任务耗时0.1秒,则需要100*0.1至1000*0.1,即10~100个线程。那么corePoolSize应该设置为大于10,具体数字最好根据8020原则,即80%情况下系统每秒任务数,若系统80%的情况下第秒任务数小于200,最多时为1000,则corePoolSize可设置为20。

queueCapacity:

LinkedBlockingQueuequeue=newLinkedBlockingQueue();

maxPoolSize:

当系统负载达到最大值时,核心线程数已无法按时处理完所有任务,这时就需要增加线程。每秒200个任务需要20个线程,那么当每秒达到1000个任务时,则需要(1000-queueCapacity)*(20/200),即60个线程,可将maxPoolSize设置为60。

keepAliveTime:

allowCoreThreadTimeout:

默认情况下核心线程不会退出,可通过将该参数设置为true,让核心线程也退出。

使用ThreadLocal解决SimpleDateFormat,

privatestaticThreadLocalthreadLocal=newThreadLocal(){@OverrideprotectedDateFormatinitialValue(){returnnewSimpleDateFormat("yyyy-MM-ddHH:mm:ss");}};

在java线程中有6个状态也就是Thread中的枚举类

NEW,RUNNABLE,WAITING,TIME_WAITING,BLOCKED,TERMINATED

应该在try{}catch{}中重新设置中断状态,因为发出中断异常被退出了。

jvm规范定了jvm内存模型来屏蔽掉各种操作系统,虚拟机实现厂商和硬件的内存访问差异,确保java程序在所有操作系统和平台上能够实现一次编写,到处运行的效果。

1.我们需要端口号来实现应用程序间的区分。

2.UDP校验和可以实现传输层的校验,虽然UDP协议不具备纠错能力,但是可以对出错的数据包进行丢弃,而IP的校验只是在校验IP报头,而不是整个数据包,整个数据包的校验是在传输层完成的,如果出错了,就会把出错的数据包丢弃。这也就是为什么需要有传输层

1.管道通信方式的中间介质是文件,通常称这种文件为管道文件。两个进程利用管道进行通信,一个进程为写进程,另一个进程为读进程。写进程通过往管道文件中写入信息,读进程通过读端从管道文件中读取信息,这样的方式进行通信。

Shutdown()方法

当线程池调用该方法时,线程池的状态则立刻变成SHUTDOWN状态。此时,则不能再往线程池中添加任何任务,否则将会抛出RejectedExecutionException(拒绝执行异常)异常。但是,此时线程池不会立刻退出,直到添加到线程池中的任务都已经处理完成,才会退出。

shutdownNow()方法

根据JDK文档描述,大致意思是:执行该方法,线程池的状态立刻变成STOP状态,并试图停止所有正在执行的线程,不再处理还在池队列中等待的任务,当然,它会返回那些未执行的任务。

它试图终止线程的方法是通过调用Thread.interrupt()方法来实现的,但是大家知道,这种方法的作用有限,如果线程中没有sleep、wait、Condition、定时锁等应用,interrupt()方法是无法中断当前的线程的。所以,ShutdownNow()并不代表线程池就一定立即就能退出,它可能必须要等待所有正在执行的任务都执行完成了才能退出。

Integer包装类是Java最基本的语法糖优化,如果我们写一段程序,通过反编译就会看到,通过的是Integer.valueOf()或者Interger.intValue()来进行转换的。

Integer和int比较会自动拆箱,

当Integer和integer比较的时候是不会自动拆箱的,除非遇到了算术符,才会调用intValue()方法去拆箱。并且在Integer中的equals是不会处理数据类型转换关系的,使用时是需要慎用,在equals方法中判断为Integer类的才会执行真正的判断流程也就是拆箱去判断,所以不会处理数据类型转换比如Long。如果是基本类型比较,编译器会隐形的把int转换为long,就可以得出正确的结论。

因为在使用suspend()去挂起线程的时候,suspend在导致线程暂停的同时,不会去释放任何锁的资源。必须要等待resume()操作,被挂起的线程才能继续。如果我们resume()操作意外地在suspend()前就执行了,那么被挂起的线程可能很难有机会被继续执行。并且,更严重的是:所占用的锁不会被释放,因此可能会导致整个系统工作不正常

yield是谦让,调用后会使当前线程让出CPU,但是注意的地方让出CPU并不表示当前线程不执行了。当前线程在让出CPU后,还会进行CPU资源的争夺,有可能刚刚一让马上又进。

1.未提交读都不能解决

2.已提交读能解决脏读

3.可重复读能解决脏读,不可重复读

4.序列化读能解决脏读,不可重复读,幻读

1.传统的虚拟机在宿主机操作系统上面会利用虚拟机管理程序去模拟完整的一个虚拟机操作系统,docker只是在操作系统上的虚拟化,直接复用本地主机的操作系统,非常轻量级。

docker启动速度一般在秒级,虚拟机启动速度一般在分钟级。

2.对于资源的使用一般是mb,一台机器可以有上千个docker容器,但是虚拟机占用资源为GB,只能支持几个。

3.性能:接近原生,由于又虚拟化了一层所以效率低。

4.docker采用类似git的命令学习升本低,指令简单。

5.虚拟机隔离性是完全隔离,容器是安全隔离

每一个词都会有一个倒排表,多个可以合并

为了标识webSocket:会在请求头中写一个upgrade:webSocket

与HTTP比较

同样作为应用层的协议,WebSocket在现代的软件开发中被越来越多的实践,和HTTP有很多相似的地方,这里将它们简单的做一个纯个人、非权威的比较:

相同点

都是基于TCP的应用层协议。

都使用Request/Response模型进行连接的建立。

在连接的建立过程中对错误的处理方式相同,在这个阶段WS可能返回和HTTP相同的返回码。

都可以在网络中传输数据。

不同点

WS使用HTTP来建立连接,但是定义了一系列新的header域,这些域在HTTP中并不会使用。

WS的连接不能通过中间人来转发,它必须是一个直接连接。

WS连接建立之后,通信双方都可以在任何时刻向另一方发送数据。f

WS连接建立之后,数据的传输使用帧来传递,不再需要Request消息。

WS的数据帧有序。

小,且只干一件事情。

独立部署和生命周期管理。

异构性

轻量级通信,RPC或者Restful。

BIO以是一客户端一线程,一个Acceptor线程来接受请求,之后为每一个客户端都创建一个新的线程进行链路处理,最大的问题缺乏弹性伸缩能力,客户端并发访问量增加后,线程数急剧膨胀。可以用线程池缓解但是还是不行。

NIO非阻塞IO解决了这个问题,一个线程就可以管理多个Socket.

在NIO中有三个需要我们了解Buffer,Channel,Selector。

Buffer:NIO是面向缓冲区,IO是面向流的。缓冲区实质上一个数组

,缓冲区不仅仅是一个数组,缓冲区提供了对数据结构化访问以及维护读写位置等信息。

通道Channel:

Channel是一个通道,网络数据通过Channel读取和写入。通道与流的不同之处在于通道是双向的,流是一个方向上移动,通道可以用于读写操作,特别是在UNIX网络编程模型底层操作系统的通道都是全双工的,同时支持读写操作。

select/poll和epoll:selectpoll顺序扫描fd,就绪就返回fd。epoll则是采用事件驱动,用回调的方式返回fd。

1.单一职责原则(SingleResponsibilityPrinciple)

每一个类应该专注于做一件事情。

2.里氏替换原则(LiskovSubstitutionPrinciple)

超类存在的地方,子类是可以替换的。

3.依赖倒置原则(DependenceInversionPrinciple)

实现尽量依赖抽象,不依赖具体实现。

4.接口隔离原则(InterfaceSegregationPrinciple)

应当为客户端提供尽可能小的单独的接口,而不是提供大的总的接口。

5.迪米特法则(LawOfDemeter)

又叫最少知识原则,一个软件实体应当尽可能少的与其他实体发生相互作用。

6.开闭原则(OpenClosePrinciple)

面向扩展开放,面向修改关闭。

7.组合/聚合复用原则(Composite/AggregateReusePrincipleCARP)

尽量使用合成/聚合达到复用,尽量少用继承。原则:一个类中有另一个类的对象。

强类型:不允许隐形转换

弱类型:允许隐形转换

静态类型:编译的时候就知道每一个变量的类型,因为类型错误而不能做的事情是语法错误.

动态类型:编译得时候不知道每一个变量的类型,因为类型错误而不能做的事情是运行时错误

编译语言和解释语言:解释性编程语言,每个语句都是执行的时候才翻译而且是一句一句的翻译就很低。

编译的语言就只需要一次就可以了

主要是继承和实现接口的两个区别,如果只想重写run方法就可以使用,如果不重写其他方法就使用runnable,如果使用实现接口的实现,让自己方便管理线程以及让线程复用,可以使用线程池去创建。

哈希表的概念:

哈希表就是一种以键-值(key-indexed)存储数据的结构,我们只要输入待查找的值即key,即可查找到其对应的值。

哈希表的实现思路:

如果所有的键都是整数,那么就可以使用一个简单的无序数组来实现:将键作为索引,值即为其对应的值,这样就可以快速访问任意键的值。这是对于简单的键的情况,我们将其扩展到可以处理更加复杂的类型的键。对于冲突的情况,则需要处理地址的冲突问题。所以,一方面要构造出良好的哈希函数,对键值集合进行哈希,另外一方面需要设计出良好的解决冲突的算法,处理哈希碰撞的冲突。

哈希表的查找步骤:

(1)使用哈希函数将被查找的键转换为数组的索引。在理想的情况下,不同的键会被转换为不同的索引值,但是在有些情况下我们需要处理多个键被哈希到同一个索引值的情况。所以哈希查找的第二个步骤就是处理冲突

(2)处理哈希碰撞冲突。有很多处理哈希碰撞冲突的方法,本文后面会介绍拉链法和线性探测法。

哈希表的思想:

哈希表的工作步骤:

1)哈希(Hash)函数是一个映象,即将关键字的集合映射到某个地址集合上,它的设置很灵活,只要这个地址集合的大小不超出允许范围即可;

2)由于哈希函数是一个压缩映象,因此,在一般情况下,很容易产生“冲突”现象,即:key1!=key2,而f(key1)=f(key2)。键不同,但是对应的取值相同。

3).只能尽量减少冲突而不能完全避免冲突,这是因为通常关键字集合比较大,其元素包括所有可能的关键字,而地址集合的元素仅为哈希表中的地址值。

哈希函数的构造方法:

1、直接地址法

以数据元素的关键字k本身或者他的线性的函数作为它的哈希地址,也就是H(k)=k,或者H(k)=a*k+b;

适用的场景:地址集合的大小==关键字的集合。

2、数字分析法

取数据元素关键字中某些取值较均匀的数字位作为哈希地址的方法

适用的场景:能预先估计出全体关键字的每一位上各种数字出现的频度。

3、折叠法

将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位),这方法称为折叠法

适用场景:关键字的数字位数特别多。

4、平方取中法

先取关键字的平方,然后根据可使用空间的大小,选取平方数是中间几位为哈希地址。

5、减去法

6、基数转换法

7、除留余数法

8、随机数法

9、随机乘数法

10、旋转法

构造哈希哈希函数的原则:

2、关键子的长度

3、哈希表的长度

4、关键字的分布的情况

5、记录查找频率

哈希函数的冲突解决的方法:

1、开放地址法

这种方法也称再散列法,其基本思想是:当关键字key的哈希地址p=H(key)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi,将相应元素存入其中。这种方法有一个通用的再散列函数形式:

Hi=(H(key)+di)%mi=1,2,…,n

其中H(key)为哈希函数,m为表长,di称为增量序列。增量序列的取值方式不同,相应的再散列方式也不同。主要有以下三种:

l线性探测再散列

dii=1,2,3,…,m-1

这种方法的特点是:冲突发生时,顺序查看表中下一单元,直到找出一个空单元或查遍全表。

l二次探测再散列

di=12,-12,22,-22,…,k2,-k2(k<=m/2)

这种方法的特点是:冲突发生时,在表的左右进行跳跃式探测,比较灵活。

l伪随机探测再散列

di=伪随机数序列。

2、再哈希法

这种方法是同时构造多个不同的哈希函数:

Hi=RH1(key)i=1,2,…,k

3、链地址法

这种方法的基本思想是将所有哈希地址为i的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。链地址法适用于经常进行插入和删除的情况。

4、建立公共溢出区

这种方法的基本思想是:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表

1.通过new

2.通过反射利用当前线程的classloader

3.自己继承实现一个classloader实现自己的类装载器

class.forName和Classloader.loadClass区别

Classloader

104.HashMap内部是怎么实现的?(拉链式结构)

存储示意图:

(1)一般情况下通过hash(key)%length实现,元素存储在数组中的索引是由key的哈希值对数组的长度取模得到。

(2)hashmap也是一个线性的数组实现的,里面定义一个内部类Entry,属性包括key、value、next.Hashmap的基础就是一个线性数组,该数组为Entry[],map里面的内容都保存在entry[]数组中。

(3)确定数组的index:hashcode%table.length

数组的下标index相同,但是不表示hashcode相同。

实现随机存储的方法:

//存储时:

inthash=key.hashCode();//这个hashCode方法这里不详述,只要理解每个key的hash是一个固定的int值

intindex=hash%Entry[].length;

Entry[index]=value;

//取值时:

inthash=key.hashCode();

returnEntry[index];

put方法的实现:

如果两个key通过hash%Entry[].length得到的index相同,会不会有覆盖的危险?

这里HashMap里面用到链式数据结构的一个概念。上面我们提到过Entry类里面有一个next属性,作用是指向下一个Entry。打个比方,第一个键值对A进来,通过计算其key的hash得到的index=0,记做:Entry[0]=A。一会后又进来一个键值对B,通过计算其index也等于0,现在怎么办?HashMap会这样做:B.next=A,Entry[0]=B,如果又进来C,index也等于0,那么C.next=B,Entry[0]=C;这样我们发现index=0的地方其实存取了A,B,C三个键值对,他们通过next这个属性链接在一起。所以疑问不用担心。也就是说数组中存储的是最后插入的元素。

get方法的实现:

先定位到数组元素,再遍历该元素处的链表

table的大小:

table的初始的大小并不是initialCapacity,是initialCapacity的2的n次幂

目的在于:当哈希表的容量超过默认的容量时,必须重新调整table的大小,当容量已经达到最大的可能的值时,这时需要创建一张新的表,将原来的表映射到该新表。

req.getSession().invalidate();销毁session

1、降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

2、提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。

3、提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

boolean单独使用的时候还会被变成int,4个字节

boolean[]数组使用的时候变成byte,1个字节

Buffer:缓冲区,用于存储速度不同步的情况,处理系统两端速度平衡,为了减小短期内突发I/O的影响,起到流量整形的作用。速度慢的可以先把数据放到buffer,然后达到一定程度在读取数据

内连接:

必须两个表互相匹配才会出现

外链接

左外链接:左边不加限制

右外连接:右边不加限制

全连接:左右都不加限制

全文检索的索引创建过程一般有以下几步:

第一步:一些要索引的原文档(Document)。

为了方便说明索引创建过程,这里特意用两个文件为例:

文件一:Studentsshouldbeallowedtogooutwiththeirfriends,butnotallowedtodrinkbeer.

文件二:MyfriendJerrywenttoschooltoseehisstudentsbutfoundthemdrunkwhichisnotallowed.

第二步:将原文档传给分词器(Tokenizer)。

分词器(Tokenizer)会做以下几件事情(此过程称为Tokenize):

1.将文档分成一个一个单独的单词。

2.去除标点符号。

3.去除停词(Stopword)。

所谓停词(Stopword)就是一种语言中最普通的一些单词,由于没有特别的意义,因而大多数情况下不能成为搜索的关键词,因而创建索引时,这种词会被去掉而减少索引的大小。

英语中停词(Stopword)如:“the”,“a”,“this”等。

对于每一种语言的分词组件(Tokenizer),都有一个停词(stopword)集合。

经过分词(Tokenizer)后得到的结果称为词元(Token)。

在我们的例子中,便得到以下词元(Token):

“Students”,“allowed”,“go”,“their”,“friends”,“allowed”,“drink”,“beer”,“My”,“friend”,“Jerry”,“went”,“school”,“see”,“his”,“students”,“found”,“them”,“drunk”,“allowed”。

第三步:将得到的词元(Token)传给语言处理组件(LinguisticProcessor)。

对于英语,语言处理组件(LinguisticProcessor)一般做以下几点:

1.变为小写(Lowercase)。

2.将单词缩减为词根形式,如“cars”到“car”等。这种操作称为:stemming。

3.将单词转变为词根形式,如“drove”到“drive”等。这种操作称为:lemmatization。

而且在此过程中,我们惊喜地发现,搜索“drive”,“driving”,“drove”,“driven”也能够被搜到。因为在我们的索引中,“driving”,“drove”,“driven”都会经过语言处理而变成“drive”,在搜索时,如果您输入“driving”,输入的查询语句同样经过我们这里的一到三步,从而变为查询“drive”,从而可以搜索到想要的文档。

ZK实现分布式锁-是否存在,并且最小的

根据ZK中节点是否存在,可以作为分布式锁的锁状态,以此来实现一个分布式锁,下面是分布式锁的基本逻辑:

客户端调用create()方法创建名为“/dlm-locks/lockname/lock-”的临时顺序节点。

客户端调用getChildren(“lockname”)方法来获取所有已经创建的子节点。

客户端获取到所有子节点path之后,如果发现自己在步骤1中创建的节点是所有节点中序号最小的,那么就认为这个客户端获得了锁。

如果创建的节点不是所有节点中需要最小的,那么则监视比自己创建节点的序列号小的最大的节点,进入等待。直到下次监视的子节点变更的时候,再进行子节点的获取,判断是否获取锁。

而且zk的临时节点可以直接避免网络断开或主机宕机,锁状态无法清除的问题,顺序节点可以避免惊群效应。这些特性都使得利用ZK实现分布式锁成为了最普遍的方案之一。

Redus实现分布式锁,使用setNX(setifnotexists)

getset(先写新值返回旧值,用于分辨是不是首次操作)防止网络断开后会设置超时

SETNX可以直接加锁操作,比如说对某个关键词foo加锁,客户端可以尝试

SETNXfoo.lock

如果返回1,表示客户端已经获取锁,可以往下操作,操作完成后,通过

DELfoo.lock

命令来释放锁。

处理死锁

C2向foo.lock发送DEL命令。

C2向foo.lock发送SETNX获取锁。

C3向foo.lock发送DEL命令,此时C3发送DEL时,其实DEL掉的是C2的锁。

C3向foo.lock发送SETNX获取锁。

此时C2和C3都获取了锁,产生竞争条件,如果在更高并发的情况,可能会有更多客户端获取锁。所以,DEL锁的操作,不能直接使用在锁超时的情况下,幸好我们有GETSET方法,假设我们现在有另外一个客户端C4,看看如何使用GETSET方式,避免这种情况产生。

C4向foo.lock发送GESET命令,

GETSETfoo.lock

AOF重写带有子进程副本保证安全

程序计数器:(线程私有)当前线程所执行的字节码的行号指示器,通过改变这个计数器的值来选取下一条需要执行的字节码的指令,以程序中分支、循环和跳转等流程的控制都离不开这个计数器的指示。

虚拟机栈:(线程私有),每个方法在执行时都会创建一个栈桢,用于存储局部变量表、操作数栈、动态链接和方法出口等信息。一个方法从调用到执行完成的过程,对应的栈桢在虚拟机栈的进出过程。当线程结束时,虚拟机栈中的数据会被自动的释放。

局部变量表:基本数据类型、对象的引用、返回地址,局部变量表锁需要的内存空间是在程序编译时就已经会被确定好的。

本地方法栈:(线程私有)虚拟机栈是为执行java方法所服务的,而本地方法栈是为了虚拟机使用到的本地方法锁服务的。

堆区:(线程共享)java堆是被所有的线程所共享的一片区域,所有的对象的实例和数组都会在堆区尽心分配。java堆细分:新生代和老年代;也可能会划分出多个线程锁共享额分配缓冲区TLAB;

Java堆可以在物理上不连续的内存空间中,只要逻辑上连续就可以。

方法区:(线程共享)存储已经被虚拟机加载过的类的信息、常量、静态变量和及时编译器编译后的代码。在方法区中一个区域叫做:运行时常量池,用于存放编译后生成的字面量和符号的引用。

堆的分代

(1)年轻代:

所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。年轻代分三个区。一个Eden区,两个Survivor区(一般而言)。

大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当一个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当另一个Survivor区也满了的时候,从前一个Survivor区复制过来的并且此时还存活的对象,将被复制“年老区(Tenured)”。

(2)年老代:

在年轻代中经历了N(可配置)次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

(3)持久代:

用于存放静态数据,如JavaClass,Method等。持久代对垃圾回收没有显著影响。

对象的创建方法,对象的内存的分配,对象的访问定位

对象的创建:

(1)第一步,当遇到一个new的指令,首先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并检查这个符号引用代表的类是否已经被加载、解析和初始化过。如果没有,需要先执行相应的类加载过程;

(2)第二步,根据类加载完成后确定的内存大小,为对象分配内存;

(3)第三步,需要对分配到的内存空间都初始化为零值;

(4)第四步,虚拟机要对对象设置一些基本信息,如对象是那个类的实例、对象的哈希码、对象的GC分代年龄信息、如何才能找到类的元数据信息等,到这里虚拟机创建对象的工作已经完成;

(5)第五步,从程序的角度,我们还需要对对象进行初始化操作。

对象的内存分配:

(1)对象头:

存储hashcode、gc分代年龄以及一些必要的自身的运行时数据

(2)实例数据:

存储真实的数据信息

(3)对齐填充:

仅仅起到占位符的作用

对象的访问定位:

通过句柄池的访问,在句柄池中保存着到对象实例数据的指针以及到对象类型的数据的指针

通过直接的指针服访问,通过引用直接指向java堆的对象的实例数据

标记清除法:

就是先标记哪些对象实例不用,然后直接清除。缺点就是产生大量的内存碎片,下次若要存储一个大的对象,无法找到连续内存而又必须提前GC

标记整理:

也就是先标记,然后对存活的对象进行移动,全部移动到一端,然后再对其它的内存进行清理。

复制算法:

把内存分成相等的AB两块,每次只使用其中的一块。比如当A内存使用完后,就把A中还存活着的对象复制到另外一块内存中去(B),然后再把已经使用过的内存清理掉。优点:这样就不用考虑内存碎片的问题了。缺点:内存减半,代价略高。

对于新生代的收集器:

Serial单线程收集器parnew多线程收集器parallelSccavenge收集器

对于老年代的收集器:

CMS并发收集低停顿收集器serialOld单线程收集器parallelOld多线程收集器

优点:并发收集、低停顿

缺点:

(1)对cpu资源非常的敏感,在并发的阶段虽然不会导致用户的线程停顿,但是会由于占用一部分的线程导致应用程序变慢,总的吞吐量会降低;

(2)无法去处理浮动垃圾;

(3)基于“标记-清除”算法的收集器,所以会出现碎片。

114、G1收集器:

优点:

(2)分代收集,不要其他收集器的配合便可以独立管理整个的GC堆;

(3)空间整合:整体基于“标记-清理”算法的实现,局部是基于“复制”算法的实现;

(4)可以预测的停顿

MinorGC:新生代GC,当jvm无法为一个新的对象分配空间时会触发

FullGC:整个堆空间的GC

类的加载:将类的class文件读入内存,并创建一个叫做java.lang.Class对象,当程序中使用任何类时,系统都会为之建立一个java.lang.Class对象。

(1)从本地文件系统中加载class文件

(2)从jar包中加载class文件,比如jdbc编程时

(3)通过网络加载class文件

(4)把一个java源文件动态编译,并执行加载

连接:

(1)验证:验证阶段用于检验被加载的类是否具有正确的内部结构,并和其他的类协调一致

(2)准备:为类的类变量分配内存,并去设置默认的值

(3)解析:将类的二进制数据中的符号引用替换成直接引用。

初始化:

主要是对类变量进行初始化。

(1)如果该类还没有被加载和连接,则先进行加载连接

(2)如果该类的直接父类还没有被初始化,则先初始化其直接父类

(3)类中如果有初始化的语句则先去执行这些初始化语句。

概念:在运行的状态中,对于任何一个类或者对象,可以知道其任意的方法和属性,这种动态地调用其属性和方法的手段叫做反射。利用的反编译的手段

一、通过三种方式来获取Employee类型,获取类:

(1)Classc1=Class.forName(“Employee”);

(2)Classc2=Employee.class;

(3)Employeee=newEmployee();Classc3=e.getClass();

二、得到class的实例:

Objecto=c1.newInstance();

三、获取所有的属性

Field[]fs=c.getDeclaredFields();

四、获取所有的方法

GetDeclareMethods();

动态代理

J2se多线程(线程锁)

线程的状态:

新建状态、就绪状态、运行状态、阻塞状态、死亡状态(线程状态转换图)

多线程的创建和启动:

(1)继承Thread类,重写类的run方法,调用对象的start方法启动

(2)实现Runnable接口,并重写该接口的run方法,该方法同样是线程的执行体,创建runnable实现类的实例,并以此实例作为Thread类的target来创建thread对象,该thread对象才是真的线程对象。

(3)使用Callable和Future接口创建线程。具体是创建Callable接口的实现类,并实现clall()方法。并使用FutureTask类来包装Callable实现类的对象,且以此FutureTask对象作为Thread对象的target来创建线程。

方法3:

//创建MyCallable对象

CallablemyCallable=newMyCallable();

//使用FutureTask来包装MyCallable对象

FutureTaskft=newFutureTask(myCallable);

//FutureTask对象作为Thread对象的target

Threadthread=newThread(ft);

//线程进入到就绪状态

thread.start();

线程同步的方法:sychronized、lock、reentrantLock等

synchronized修饰同步监视器:修饰可能被并发访问的共享资源充当同步监视器;

synchronized修饰方法,同步方法的同步监视器是this,也就是调用该方法的对象;

synchronizedd可以用来修饰方法,可以修饰代码块,但是不能修饰构造器和成员变量;

使用lock锁对象,每次只能有一个线程对lock对象进行加锁和释放锁,线程开始访问该锁对象时必须先获得锁lock

基本用法:

PrivatefinalReentrantLocklock=newReentrantLock();

Lock.lock();

Try(){

}catch(Exceptione){

}finally{}

Lock.unlock();

锁的等级:内置锁、对象锁、类锁、方法锁。

内置锁:每一个java对象都可以用做一个实现同步的锁,这个锁成为内置锁。当一个线程进入同步代码块或者方法的时候会自动获得该锁,在退出同步代码块或者方法时会释放该锁。

获得内置锁的方法:进入这个锁的保护的同步代码块或者方法

注意:java内置锁是一个互斥锁,最多只有一个线程能够获得该锁。

对象锁:对象锁是用于对象实例方法,或者一个对象实例上的。

类锁:类锁用于类的静态方法或者一个类的class对象上,一个类的对象实例有多个,但是每个类只有一个class对象,即不同对象实例的对象锁是互不干扰的,每一个类都有一个类锁。类锁只是概念上的,并不是真实存在的。

方法锁:synchronized修饰方法,同步方法的同步监视器是this,也就是调用该方法的对象;

作用:

ThreadLocal类只能去创建一个被线程访问的变量,如果一段代码含有一个ThreadLocal变量的引用,即使两个线程同时执行这段代码,它们也无法访问到对方的ThreadLocal变量。

创建ThreadLocal的方式:

privateThreadLocalmyThreadLocal=newThreadLocal();

我们可以看到,通过这段代码实例化了一个ThreadLocal对象。

我们只需要实例化对象一次,并且也不需要知道它是被哪个线程实例化。

虽然所有的线程都能访问到这个ThreadLocal实例,但是每个线程却只能访问到自己通过调用ThreadLocal的set()方法设置的值。即使是两个不同的线程在同一个ThreadLocal对象上设置了不同的值,他们仍然无法访问到对方的值。

如何为ThreadLocal对象赋值和取值:

一旦创建了一个ThreadLocal变量,你可以通过如下代码设置某个需要保存的值:

myThreadLocal.set("Athreadlocalvalue”);

可以通过下面方法读取保存在ThreadLocal变量中的值:

StringthreadLocalValue=(String)myThreadLocal.get();

get()方法返回一个Object对象,set()对象需要传入一个Object类型的参数。

初始化该ThreadLocal变量:

通过创建一个ThreadLocal的子类重写initialValue()方法,来为一个ThreadLocal对象指定一个初始值。

优势:

第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。

第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。但是要做到合理的利用线程池,必须对其原理了如指掌。

用法:

线程池的创建:

newThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,milliseconds,runnableTaskQueue,handler);

参数:corePoolSize:线程池的基本大小

maximumPoolSize:线程池的最大大小

runnableTaskQueue:任务队列

执行方式:

threadsPool.execute(handler);

threadsPool.submit(handler);

线程池的关闭:

Shutdown和shutdownNow方法实现

线程池的工作流程分析:

先将任务提交的顺序为核心线程池、队列、线程池、当这三个关节都不能执行用户所提交的线程时,则抛出“无法执行的任务”。

(1)java中字节流处理的最基本的单位是单个字节。通常用来处理二进制数据,最基本的两个字节流类是InputStream和OutputStream,这两个类都为抽象类。

字节流在默认的情况下是不支持缓存的。每次调用一次read方法都会请求操作系统来读取一个字节,往往会伴随一次磁盘的IO,如果要使用内存提高读取的效率,应该使用BufferedInputStream。

(2)字符流处理的最基本的单元是unicode(码元),通常用来来处理文本数据。

输入字符流(文件到内存):把要读取的字节序列按照指定的编码方式解码为相应的字符序列,从而可以存在内存中。

输出字符流(内存到文件):把要写入文件的字符序列转为指定的编码方式下的字节序列,然后写入文件中。

区别如下:

1、字节流操作的基本单元为字节;字符流操作的基本单元为Unicode码元。

unicode的编码范围:0x0000~0XFFFF,在这个范围的每个数字都有一个字符与之对应

2、字节流默认不使用缓冲区;字符流使用缓冲区。

3、字节流通常用于处理二进制数据,实际上它可以处理任意类型的数据,但它不支持直接写入或读取Unicode码元;字符流通常处理文本数据,它支持写入及读取Unicode码元。

含义:

java序列化:将java对象转换为字节序列的过程;

java反序列化:将字节序列恢复为java对象的过程

序列化的目的:

实现数据的持久化,将数据永久地保存在磁盘上,通常放在文件中;

利用序列化实现远程的通讯,在网络上传送对象的字节序列.

实现序列化的三种方法:

(1)某实体类仅仅实现了serializable接口(常用)

序列化步骤:

步骤一:创建一个对象输出流,它可以包装一个其它类型的目标输出流,如文件输出流:

ObjectOutputStreamout=newObjectOutputStream(newfileOutputStream(“D:\\objectfile.obj”));

步骤二:通过对象输出流的writeObject()方法写对象:

//Hello对象的字节流将输入到文件

out.writeObject(“Hello”);

反序列化步骤:

步骤一:创建一个对象输入流,它可以包装一个其它类型输入流,如文件输入流:

ObjectInputStreamin=newObjectInputStream(newfileInputStream(“D:\\objectfile.obj”));

步骤二:通过对象输出流的readObject()方法读取对象:

//将从文件中读取到字节序列转化为对象

Stringobj1=(String)in.readObject();

(2)若实体类仅仅实现了Serializable接口,并且还定义了readObject(ObjectInputStreamin)和writeObject(ObjectOutputSteamout),则采用以下方式进行序列化与反序列化。

ObjectOutputStream调用该对象的writeObject(ObjectOutputStreamout)的方法进行序列化。

ObjectInputStream会调用该对象的readObject(ObjectInputStreamin)的方法进行反序列化。

(3)若Student类实现了Externalnalizable接口,且Student类必须实现readExternal(ObjectInputin)和writeExternal(ObjectOutputout)方法,则按照以下方式进行序列化与反序列化。

ObjectOutputStream调用Student对象的writeExternal(ObjectOutputout))的方法进行序列化。

ObjectInputStream会调用Student对象的readExternal(ObjectInputin)的方法进行反序列化。

1)在执行的速度上:StringBuilder>StringBuffer>String

2)String是字符串常量StringBuffer和StringBuilder是字符串变量

例子1:

Strings=“abcd”;

s=s+1;

Syos(s);

底层执行:首先创建一个对象s,赋予abcd.然后又创建新的对象s,之前的对象并没有发生变化,利用string操作字符串时,是在不断创建新的对象,而原来的对象由于没有了引用,会被GC,这样执行的效率会很低。

例子2:

Stringstr2=“Thisisonlya”;

Stringstr3=“simple”;

Stringstr4=“test”;

Stringstr1=str2+str3+str4;

同理:str2str3str3没有被引用,但是创建了新的对象str1,执行速度上会很慢。

StringBuilder:线程非安全的

StringBuffer:线程安全的

例子3:

StringBufferbuilder=newStringBuilder(“Thisisonlya”).append(“simple”).append(“test”);

应用场景:

A:使用要操作少量的数据时,使用String

B:单线程操作字符串缓冲区下操作大量数据使用StringBulider

C:多线程操作字符串缓冲区下操作大量的数据使用StringBuffer

HashMap是线程不安全的;允许有null的键和值;执行的效率高一点;方法不是synchronize的要提供外同步;包含有containsvalue和containskey的方法

HashTable是线程安全的;不允许有null的键和值;效率稍微低些;方法是synchronize的;包含contains方法

(参看博客)

==:对于基本数据类型的变量,直接比较存储的值是否相等;作用于引用类型的变量,则比较的是该变量所指向的地址是否相同。

equals:不同作用于基本数据类型的变量,如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址(相当于直接使用父类的equals方法,而该方法则是用==进行的比较,所以结果和用==比较的效果是一样的);但是比如StringDate类对equals进行了重写,比较的是字面量。

对于基本的数据类型,使用final关键字将使得数值恒定不变;

对于对象引用,final则是引用恒定不变,一但被初始化指向一个对象,它就不会再指向另外一个对象,但是该对象本身是可以被修改的;

对于类,如果不想继承某个类,可以将该类设置为fianl形式,该类不会有子类;

对于方法,final修饰的方法不会被重写

对于空白的final,对于没有给定初始值的fianl,编译器会在使用前初始化该final修饰的变量

对于宏变量:被final修饰的变量为宏常量在编译的阶段被其本身的值直接替换

shorts1=1;s1=s1+1;

表达式类型的自动提升,一个short类型的变量和一个int型的数在一起进行运算,会将short类型的数隐式转换为int参与运算,但是该运算的结果为int类型是不同直接赋值给一个short类型的,必须进行强制的类型转换,否则编译是通不过的。

类型转换:byte(1字节)--->short(1)/char(2)--->int(4)--->long(8)--->float(4)--->double(8)

分装类:ByteShortCharacterIntegerLongFloatDouble

(1)在jdk1.7版本前不支持string作为参数,仅仅支持byte、short、char,因为可以转换为int,但是long和string不能转换为int,所以不能使用。

(2)在jdk1.7之后,支持使用string作为case的参数,实际匹配的是该字符串的hash值,然后用equals进行安全性检查。Switch支持String其实是一个语法糖,在编译后的字节码文件中都会被还原成原生的类型,并在相应的位置插入强制转换的代码,底层的JVM在switch上并没有修改;当传入switch是null时,在运行时对一个null调用hashcode()方法,会抛出空指针异常。

object是所有类的父类,任何类都默认继承Object类

9、Clone

private保护方法,实现对象的浅复制,只有类实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportException

10、Equals

11、hashCode

12、getClass

13、wait方法

14、Notify

15、notifyAll

16、toString

引用的级别:

强引用>软引用>弱引用>虚引用

强引用:如果一个对象具有强引用,垃圾回收器绝对不会回收它。当内存空间不足时,jvm宁愿抛出outofmemoryError,使得程序的异常终止。

软引用:如果一个对象具有软引用,则内存空间足够,垃圾回收机制就不会去回收它,当内存不足时,就会进行回收。如果软引用所引用的对象被垃圾回收器回收,java虚拟机就会把这个软引用加入到与之关联的引用队列。

应用场景:实现内存敏感的高速缓存

弱引用:在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。

应用场景:gc运行后终止

虚引用:就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

(1)Hashcode的存在主要用于解决查找的快捷性,比如在hashmap、hashtable中,hashcode是用来在散列的存储结构中确定对象的存储的位置的。

(2)如果两个对象相同,就是通过equals方法比较返回true,两个对象装在一个桶里,也就是hashcode也要一定相同。

(3)两个对象的hashcode相同,并不一定代表两个对象就是相同的,只能说明他们存储在一个桶里。

(4)一般重写了equals方法,也尽量去重写hashcode方法,保证先找到该桶,再去找到对应的类,通过equals方法进行比较。

1、ArrayList:是基于动态数组的数据结构,LinkedList的基于链表的数据结构

2、对于随机访问get和set,ArrayList性能较好,因为LinkedList会去移动指针

3、对于新增和删除的操作,linkedList只需要修改指针的指向,性能较好,但是arrayList会移动数据。

vector的特点:

1、vector的方法都是线程同步的,是线程安全的,但是arraylist和linkedlist不是,由于线程的同步必然会影响性能,所以vector的性能不太高。

2、当vector或者arraylist的元素超过它的初始的大小时,vector会将容量翻倍,但是arraylist只会增加50%,这样有利于节约内存的空间。

hashMap不是线程安全的;

concurrentHashMap是线程安全的;在其中引入了“分段锁”,而不是将所有的方法加上synchronized,因为那样就变成了hashtable.

所谓“分段锁”,就是把一个大的Map拆分成N个小的hashtable,根据key.hashcode()决定把key放在哪一个hashtable中。

通过把整个Map分为N个Segment(类似HashTable),可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。

HashMap:根据键的hashcode值进行存储数据,根据键可以直接获取它的值,具有快速访问的特点,遍历时取得数据是随机的,hashmap最多只允许一条记录的键为null(set无序不重复),允许多条记录的值为Null;如果要保证线程的同步,应该使用Collections.synchronizedMap()方法进行包装,或者使用ConcurrentHashMap

LinkedHashMap:保存了记录的插入的顺序,在迭代遍历Linkedhashmap时,先得到的记录肯定是先插入的,它遍历的速度只和实际的数据有关和容量没关。

TreeMap:实现的是SortMap,能够把保存的记录按照键进行排序,默认会按照键值的升序进行排序,当遍历TreeMap时得到的记录是排序过后的。

Collection包结构,与Collections的区别。

Collection是一个集合的接口,提供了对集合对象进行操作的通用的方法。

在它下面的子接口:set、list、map

java.util.Collections是一个包装的类,包含有各种的有关集合操作的静态方法,比如包含对集合的搜索、排序、线程安全化等一系列的操作,此类不能被实例化,相当于是操作集合的工具类,服务于java的collection的框架。

介绍下Concurrent包

concurrent包基本有3个package组成

(1)java.util.concurrent:提供大部分关于并发的接口和类,如BlockingQueue,Callable,ConcurrentHashMap,ExecutorService,Semaphore等

(2)java.util.concurrent.atomic:提供所有原子操作的类,如AtomicInteger,AtomicLong等;

concurrent包的优点:

1.首先,功能非常丰富,诸如线程池(ThreadPoolExecutor),CountDownLatch等并发编程中需要的类已经有现成的实现,不需要自己去实现一套;毕竟jdk1.4对多线程编程的主要支持几乎就只有Thread,Runnable,synchronized等

2.concurrent包里面的一些操作是基于硬件级别的CAS(compareandswap),就是在cpu级别提供了原子操作,简单的说就可以提供无阻塞、无锁定的算法;而现代cpu大部分都是支持这样的算法的;

Try-catch-finally,try里有return,finally还执行么?

任然会执行。

1、不管有木有出现异常,finally块中代码都会执行;

2、当try和catch中有return时,finally仍然会执行;

3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,不管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;

4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。

封装:

继承:

是子对象可以继承父对象的属性和行为,亦即父对象拥有的属性和行为,其子对象也就拥有了这些属性和行为。

多态:

java的引用变量有两种类型,一个是编译时的类型,一个是运行时的类型,编译时类型由申明该变量时的类型决定,运行时的类型由实际赋值给该变量的对象所决定,如果编译时的类型和运行时的类型不一致就可能出现所谓的多态。

在java中把一个子类的对象直接赋值给一个父类的引用变量,当运行该引用变量的方法时,其方法行为总是表现出子类方法的行为特征,这就有可能出现,相同类型的变量,调用同一个方法时呈现多种不同的行为特征,出现了“多态”

Overload:方法重载,在同一个类中,方法名相同,参数列表不同,至于方法的修饰符,反回值的类型,与方法的重载没有任何的联系。

Override:方法重写,两同两小一大

两同:方法名称相同、参数列表相同

两小:返回值类型要小或者相等;抛出的异常要小或者相等

一大:子类方法的访问权限要相等或者更大

实例化:

都不能被实例化

类:一个类只能继承一次abstract类;一个类可以实现多个interface

数据成员:可以有自己的;接口的数据成员必须定义成staticfinal的

方法:可以有私有的,非abstract方法必须实现;接口中不可以有私有的方法,默认都是publicabstract的

变量:可以有私有的,其值可以在子类中重新定义,也可以重新赋值;接口中不可以有私有的成员变量,默认是publicstaticfinal实现类中不能去重新定义和改变其值

IO是面向流的,NIO是面向缓冲区

JavaNIO和IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。JavaIO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。JavaNIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。

阻塞与非阻塞IO

选择器(Selectors)

JavaNIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。

反射的作用原理。

见博客

(1)sleep方法,该方法属于thread类;wait方法属于object类

For循环可以从前向后遍历,也可以从后向前遍历,可以不逐个遍历,通常用于已知次数的循环。

foreach循环不能向迭代变量赋值,通常对集合对象从头到位进行读取,其有优化的存在。

1、指针

java语言不提供指针,增加了自动的内存管理,有效的防止c/c++中的指针操作失误。

2、多重继承

C++支持多重继承,java不支持多重继承,但是允许实现多个接口。

3、数据类型和类

java将数据和方法结合起来,分装到类中,每个对象都可以实现自己的特点和方法;而c++允许将函数和变量定义全局的。

4、内存管理

java可以对所有的对象进行内存管理,自动回收不再使用的对象的内存;c++必须由程序员显式分配内存释放内存。

5、操作符的重载

C++支持操作符的重载,java不允许进行操作符的重载。

6、预处理功能

java不支持预处理功能,c++有一个预编译的阶段,也就是预处理器。

7、字符串

C++不支持字符串,java中支持字符串,是java的类对象。

8、数组

java引入了真正的数组,不同于c++中利用指针实现的伪数组。

9、类型的转换

C++中有时会出现数据类型的隐含转换,设计到自动强制类型的转换问题,比如存在将浮点数直接转换为整数的情况,java不支持自动的强制类型转换,如果需要,必须显示进行强制的类型转换。

10、异常

java中使用try{}catch(){}finally{}进行异常的处理,c++没有。

(1)cookie数据存放在客户的浏览器上,session数据放在服务器上。

(2)cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,如果主要考虑到安全应当使用session。

(4)单个cookie在客户端的限制是4K,就是说一个站点在客户端存放的COOKIE不能4K。

(5)所以:将登陆信息等重要信息存放为SESSION;其他信息如果需要保留,可以放在COOKIE中

ACK:tcp协议规定,只有ack=1时才有效,在连接建立后所有发送的豹纹的ack=1

Syn(SYNchronization):在连接建立时用来同步序号。

当SYN=1而ACK=0:这是一个连接请求报文;

当对方同意建立连接时,则应该使得SYN=1而且ACK=1;

当SYN=1:这是一个连接请求或者连接接受报文

FIN(finis):终结的意思,用来释放一个连接。当fin=1,表示次报文段的发送方的数据已经发送完毕并要求释放连接。

A的状态:关闭状态--->同步已发送--->已建立

B的状态:关闭状态--->监听状态--->同步收到--->已建立

A:建立状态--->终止等待1--->终止等待2--->等待2MSL

B:建立状态--->关闭等待--->最后确认

Timewait的作用?

(2)SYN攻击防范

OSI模型:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层

TCP/IP模型:应用层、传输层、网络互联层、主机到网络层

协议:

(1)应用层:FTP、TELNET、HTTP|SNMP、TFTP、NTP

将OSI模型的会话层和表示层整合成应用层,应用层面向不同的网络应用引入了不同的应用层协议。

(2)传输层:TCP|UDP

功能是使得源端主机和目标端主机上的对等实体可以进行会话,定义了两种服务质量不同的协议,分别是TCP和UDP协议。

TCP协议是一个面向连接的、可靠的协议。它将一台主机发出的字节流无差错地发往互联网上的其他主机。在发送端,它负责把上层传送下来的字节流分成报文段并传递给下层。在接收端,它负责把收到的报文进行重组后递交给上层。TCP协议还要处理端到端的流量控制,以避免缓慢接收的接收方没有足够的缓冲区接收发送方发送的大量数据。

UDP协议是一个不可靠的、无连接协议。主要适用于不需要对报文进行排序和流量控制的场合。

(3)网络互联层:IP

网络互联层是整个TCP/IP协议栈的核心。功能是把分组发往目标网络或者主机。为了尽快发送分组,可能会沿着不同的路径同时进行分组传递。因此,分组到达的顺序和发送的顺序可能会不一致,这就需要上层必须对分组进行排序。同时它可以将不同类型的网络进行互联,完成拥塞控制的功能。

(4)主机到网络层:以太网、令牌环网、PPP

该层未被定义,具体的实现方式随着网络类型的不同而不同。

拥塞控制:防止过多的数据注入到网路,使得网络中的路由器和链路不至于过载。拥塞控制是一个全局的过程,和流量控制不同,流量控制是点对点的通信量的控制。

慢开始和拥塞避免:

发送方维持一个叫做拥塞窗口的状态变量,拥塞窗口取决于网络的拥塞程度,并且会动态的变化。发送方让自己的发送窗口等于拥塞窗口,考虑接受方的接受能力,发送窗口可能会小于拥塞窗口。

慢开始算法:不要一开始就发送大量的数据,先探测下网络的拥塞程度,由小到大逐渐增加拥塞窗口的数量。

结合使用:为了防止拥塞窗口增长过大引发网络的拥塞,设置一个慢开始门限ssthresh状态变量。其用法:

当cwnd使用慢开始算法

当cwnd>ssthresh,使用拥塞避免算法

当cwnd=ssthresh,慢开始算法和拥塞避免算法随意。

当遇到网络拥塞时,就把慢开始门限设置为出现拥塞时发送窗口大小的一半,同时将拥塞的窗口设置为1,再重新开始执行慢开始算法。

窗口:是一段可以被发送者发送的字节序列,其连续的范围称为“窗口”

滑动:这段“允许发送的范围”是随着发送的过程而不断变换的,表现的形式就是“按照顺序滑动”

流量控制:

(1)TCP利用滑动窗口实现流量的控制机制

(2)如何考虑流量控制中的传输效率

流量控制,接受方传递信息给发送方,使其发送数据不要太快,是一种端到端的控制,主要的方式是返回的ack中会包含自己的接受的窗口的大小,发送方收到该窗口的大小时会控制自己的数据发送。

传递效率:单个发送字节单个确认,和窗口有一个空余即通知发送方发送一个字节,会增加网络中许多不必要的报文,因为会为一个字节数据添加40个字节的头部。

2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付。

3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的

4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信

5、TCP首部开销20字节;UDP的首部开销小,只有8个字节

6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠

紧急比特URG:URG=1,注解该报文应该尽快送达,而不需要按照原来的的队列次序依次送达

确认比特ACK:只有当ACK=1,确认序号字段才有意义

急迫比特PSH:当PSH=1时,注解恳求远地TCP将本报文段立即传送给应用层

复位比特RST:当注解呈现严重错误时,必须开释连接,进行重新的传输连接

同步比特SYN:当SYN=1而ACK=0时,这是一个连接请求报文段,若对方赞成连接请求会将SYN=1而且ACK=1

终止比特FIN:当FIN=1,注解字符串已经发送完毕,并请求开释传输连接。

HTTP请求报文:(1)请求行+(2)请求头部+(3)请求正文

(1)请求行:请求方法+URL+协议版本

请求方法:常用GET、POST

协议版本:HTTP/主版本号.次版本号常用HTTP/1.0和HTTP/1.1

(2)为请求报文添加的一些附加的信息,“名/值”组成,并且是每行一对用冒号进行分割

在请求头部存在空行,表示请求头部的结束,接下来是请求正文!

区别get和post方式

对于get方式没有请求的正文,对于post方式有请求的正文。

HTTP响应的报文格式:

(1)状态行+(2)响应头部+(3)响应正文

(1)状态行:协议版本+状态码+状态码描述

(2)响应头部:也是由键值对所组成

(3)响应正文,由服务器端接受数据

(1)OPTIONS:返回服务器针对特定资源所支持的HTTP请求方法。也可以利用向Web服务器发送'*'的请求来测试服务器的功能性。

(2)HEAD:向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息。

(3)GET:向特定的资源发出请求。

(4)POST:向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的创建和/或已有资源的修改。

(5)PUT:向指定资源位置上传其最新内容。

(6)DELETE:请求服务器删除Request-URI所标识的资源。

(7)TRACE:回显服务器收到的请求,主要用于测试或诊断。

(8)CONNECT:HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。

GET方式和POST方式对比:

GET方式:请求数据放在HTTP包头;使用明文传送,不安全;长度较小,一般为1024B;应用的场景为查询数据;如果传送的是英文数字或者是数字,直接发送,如果传送的是中文字符或则是其他的字符,则会进行BASE64编码

POST方式:请求数据放在HTTP正文;可明文或者密文传送,较为安全;长度一般没有限制;应用在修改数据上。

(1)HTTP1.0规定浏览与服务器只是保持短暂的连接,浏览器每次请求都需要和服务器建立一个TCP连接,服务器完成请求处理后立即断开TCP连接,服务器不去跟踪每个客户也不去记录每个客户过去的请求。HTTP1.0不支持HOST请求字段

(2)HTTP1.1支持久连接,在一个TCP上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟;

允许客户端不用等待上一次请求的返回结果,就可以去发送下一个请求,但是服务器端必须按照接受的客户端请求的先后顺序依次会送响应的结果,这样客户端才能够区分出每次请求的响应的内容。

HTTP1.0支持HOST请求字段,这样就可以使用一个IP地址和端口号,在此基础上使用不同的主机名创建多个虚拟的WEB站点;

HTTP1.1提供了与身份认证、状态管理和cache缓存等机制

当web服务器看到keep-alive值时,会建立长连接。

步骤1:当访问www.baidu.com时,会先从本地的host文件中获取该域名对应的IP地址,如果找不到就会用DNS协议来获取IP,在该DNS协议中,计算机会由本地的DNS服务器来解析该域名,最终找到对应的IP地址。

步骤2:接下来是使用TCP协议,建立TCP连接,在建立连接之前需要,为了将给服务器的消息带给服务器,则需要OSPF\IP\ARP协议的支持,IP告诉该消息从哪里出发,去向那里;消息的传送会经过一个个的路由器,OSPF会利用路由算法找出最佳的通往目的地址的路径;ARP负责找到下一个节点的地址,ARP协议使用的MAC地址,整个的发送的过程涉及到每一个节点的MAP地址。

A类地址:1个字节的网络号+3个字节的主机地址0.0.0.0~126.255.255.255

B类地址:2个字节的网络号+2个字节的主机地址128.0.0.0~191.255.255.255

C类地址:3个字节的网络号+1个字节的主机地址192.0.0.0~223.255.255.255

D类地址:多播地址

E类地址:保留为今后使用

交换机:为数据桢从一个端口到另外一个端口的转发提供了低时延、低开销的通路,使得任意端口接受的数据帧都能够从其他的端口送出。

路由器:网络连接和路由选择,用于网络层的数据转发。

①数据库的优化,包括合理的事务隔离级别、SQL语句优化、索引的优化

②使用缓存,尽量减少数据库IO

③分布式数据库、分布式缓存

④服务器的负载均衡

工厂方法模式

抽象工厂模式

职责链模式

使得多个对象都有机会去处理请求,从而避免请求的发送者和接受者之间的耦合关系,将这些对象连成一条链,并沿着这条链去传递该请求,直到有一个对象处理它为之。

单例模式

(2)恶汉式的单例模式

(6)懒汉式实现单例模式

(7)双重锁实现的单例模式

privatestaticSingletoninstance=null;

(8)静态内部类实现单例模式

(9)枚举单例

INSTANCE;

适配器模式

将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口步兼容而不能一起工作的类变得可以一起工作。

target是我们所期望的接口的类型,包含一个request方法,通过使用adapter去实现该接口,并实现其中的request方法,在adapter中建立一个私有的adaptee对象,在adapter重写的方法中去调用specificRequest方法,这样适配器adapter就构建好了。只需要在客户端,创建adapter实例,调用request方法就可以利用多态的方式,实现了specificRequest()方法。

观察者模式

定义了一种一对多的依赖关系,让多个观察者可以同时去监听某一个主题对象,这个主题对象在状态发生变化时,会通知所有的观察者对象,使得他们能够自动更新自己。

Subject:把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者,可以增加删除观察者对象。

Observer:抽象观察者,为所有的具体的观察者定义一个接口,在得到主题时更新自己。

concreteObserver:具体的观察者,实现更新的方法

concreteSubject:具体的主题

作用:应用在一个对象改变时,需要改变其他的对象,而且具体不知道有多少个对象需要改变,将耦合的双方都依赖于抽象而不是依赖于具体,从而使得各自的变化都不会影响到另外一边的变化。

大整数BigInteger大浮点数BigDecimal

java运算的优先级:优先级相同时比较结合性:

java高并发

进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(textregion)、数据区域(dataregion)和堆栈(stackregion)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。

一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。

区别不同a,地址空间:进程内的一个执行单元;进程至少有一个线程;它们共享进程的地址空间;而进程有自己独立的地址空间;b,资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资c,线程是处理器调度的基本单位,但进程不是.d,二者均可并发执行.

在Java中有两类线程:用户线程(UserThread)、守护线程(DaemonThread)。守护线程和用户线程的区别在于:守护线程依赖于创建它的线程,而用户线程则不依赖。举个简单的例子:如果在main线程中创建了一个守护线程,当main方法运行完毕之后,守护线程也会随着消亡。而用户线程则不会,用户线程会一直运行直到其运行完毕。在JVM中,像垃圾收集器线程就是守护线程。

NEW状态是指线程刚创建,尚未启动

BLOCKED这个状态下,是在多个线程有同步操作的场景,比如正在等待另一个线程的synchronized块的执行释放,也就是这里是线程在等待进入临界区

WAITING这个状态下是指线程拥有了某个锁之后,调用了他的wait方法,等待其他线程/锁拥有者调用notify/notifyAll一遍该线程可以继续下一步操作,这里要区分BLOCKED和WATING的区别,一个是在临界点外面等待进入,一个是在理解点里面wait等待别人notify,线程调用了join方法join了另外的线程的时候,也会进入WAITING状态,等待被他join的线程执行结束

TERMINATED这个状态下表示该线程的run方法已经执行完毕了,基本上就等于死亡了(当时如果线程被持久持有,可能不会被回收)

wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁;

sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要处理InterruptedException异常;

notify():唤醒一个处于等待状态的线程,当然在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且与优先级无关;

notityAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,只有获得锁的线程才能进入就绪状态;

sleep来自Thread类,和wait来自Object类

调用sleep()方法的过程中,线程不会释放对象锁。而调用wait方法线程会释放对象锁

sleep睡眠后不出让系统资源,wait让出系统资源其他线程可以占用CPU

总体的结论先摆出来:

Volatile和Synchronized四个不同点:

粒度不同,前者针对变量,后者锁对象和类

syn阻塞,volatile线程不阻塞

syn保证三大特性,volatile不保证原子性

syn编译器优化,volatile不优化要使volatile变量提供理想的线程安全,必须同时满足下面两个条件:

对变量的写操作不依赖于当前值。

该变量没有包含在具有其他变量的不变式中。

CAS是乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。

通过Unsafe类可以分配内存,可以释放内存;类中提供的3个本地方法allocateMemory、reallocateMemory、freeMemory分别用于分配内存,扩充内存和释放内存,与C语言中的3个方法对应。

可以定位对象某字段的内存位置,也可以修改对象的字段值,即使它是私有的;

挂起与恢复:将一个线程进行挂起是通过park方法实现的,调用park后,线程将一直阻塞直到超时或者中断等条件出现。unpark可以终止一个挂起的线程,使其恢复正常。整个并发框架中对线程的挂起操作被封装在LockSupport类中,LockSupport类中有各种版本pack方法,但最终都调用了Unsafe.park()方法。

线程池的作用:在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。第三:提高线程的可管理性。常用线程池:ExecutorService是主要的实现类,其中常用的有Executors.newSingleThreadPool(),newFixedThreadPool(),newcachedTheadPool(),newScheduledThreadPool()。

构造方法参数说明

threadFactory:线程工厂,提供创建新线程的功能。ThreadFactory是一个接口,只有一个方法

原理

如果当前池大小poolSize小于corePoolSize,则创建新线程执行任务。

如果当前池大小poolSize大于corePoolSize,且等待队列未满,则进入等待队列

如果当前池大小poolSize大于corePoolSize且小于maximumPoolSize,且等待队列已满,则创建新线程执行任务。

如果当前池大小poolSize大于corePoolSize且大于maximumPoolSize,且等待队列已满,则调用拒绝策略来处理该任务。

线程池里的每个线程执行完任务后不会立刻退出,而是会去检查下等待队列里是否还有线程任务需要执行,如果在keepAliveTime里等不到新的任务了,那么线程就会退出。

13、Executor拒绝策略

AbortPolicy:为java线程池默认的阻塞策略,不执行此任务,而且直接抛出一个运行时异常,切记ThreadPoolExecutor.execute需要trycatch,否则程序会直接退出.

DiscardPolicy:直接抛弃,任务不执行,空方法

DiscardOldestPolicy:从队列里面抛弃head的一个任务,并再次execute此task。

CallerRunsPolicy:在调用execute的线程里面执行此command,会阻塞入

用户自定义拒绝策略:实现RejectedExecutionHandler,并自己定义策略模式

newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO,LIFO,优先级)执行适用场景:任务少,并且不需要并发执行

newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行

CopyOnWriteArrayList:写时加锁,当添加一个元素的时候,将原来的容器进行copy,复制出一个新的容器,然后在新的容器里面写,写完之后再将原容器的引用指向新的容器,而读的时候是读旧容器的数据,所以可以进行并发的读,但这是一种弱一致性的策略。使用场景:CopyOnWriteArrayList适合使用在读操作远远大于写操作的场景里,比如缓存。

16、AQS

AQS使用一个int成员变量来表示同步状态,通过内置的FIFO队列来完成获取资源线程的排队工作。

privatevolatileintstate;//共享变量,使用volatile修饰保证线程可见性

1

2种同步方式:独占式,共享式。独占式如ReentrantLock,共享式如Semaphore,CountDownLatch,组合式的如ReentrantReadWriteLock

节点的状态CANCELLED,值为1,表示当前的线程被取消;SIGNAL,值为-1,表示当前节点的后继节点包含的线程需要运行,也就是unpark;CONDITION,值为-2,表示当前节点在等待condition,也就是在condition队列中;PROPAGATE,值为-3,表示当前场景下后续的acquireShared能够得以执行;值为0,表示当前节点在sync队列中,等待着获取锁。

模板方法模式protectedbooleantryAcquire(intarg):独占式获取同步状态,试着获取,成功返回true,反之为falseprotectedbooleantryRelease(intarg):独占式释放同步状态,等待中的其他线程此时将有机会获取到同步状态;protectedinttryAcquireShared(intarg):共享式获取同步状态,返回值大于等于0,代表获取成功;反之获取失败;protectedbooleantryReleaseShared(intarg):共享式释放同步状态,成功为true,失败为falseAQS维护一个共享资源state,通过内置的FIFO来完成获取资源线程的排队工作。该队列由一个一个的Node结点组成,每个Node结点维护一个prev引用和next引用,分别指向自己的前驱和后继结点。双端双向链表。

独占式:乐观的并发策略acquirea.首先tryAcquire获取同步状态,成功则直接返回;否则,进入下一环节;b.线程获取同步状态失败,就构造一个结点,加入同步队列中,这个过程要保证线程安全;c.加入队列中的结点线程进入自旋状态,若是老二结点(即前驱结点为头结点),才有机会尝试去获取同步状态;否则,当其前驱结点的状态为SIGNAL,线程便可安心休息,进入阻塞状态,直到被中断或者被前驱结点唤醒。releaserelease的同步状态相对简单,需要找到头结点的后继结点进行唤醒,若后继结点为空或处于CANCEL状态,从后向前遍历找寻一个正常的结点,唤醒其对应线程。

共享式:共享式地获取同步状态.同步状态的方法tryAcquireShared返回值为int。a.当返回值大于0时,表示获取同步状态成功,同时还有剩余同步状态可供其他线程获取;b.当返回值等于0时,表示获取同步状态成功,但没有可用同步状态了;c.当返回值小于0时,表示获取同步状态失败。

7个阻塞队列。分别是

ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。DelayQueue:一个使用优先级队列实现的无界阻塞队列。SynchronousQueue:一个不存储元素的阻塞队列。LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。

添加元素

Java中的阻塞队列接口BlockingQueue继承自Queue接口。BlockingQueue接口提供了3个添加元素方法。add:添加元素到队列里,添加成功返回true,由于容量满了添加失败会抛出IllegalStateException异常offer:添加元素到队列里,添加成功返回true,添加失败返回falseput:添加元素到队列里,如果容量满了会阻塞直到容量不满

删除方法

3个删除方法poll:删除队列头部元素,如果队列为空,返回null。否则返回元素。remove:基于对象找到对应的元素,并删除。删除成功返回true,否则返回falsetake:删除队列头部元素,如果队列为空,一直阻塞到队列有元素并删除

对Condition的源码理解,主要就是理解等待队列,等待队列可以类比同步队列,而且等待队列比同步队列要简单,因为等待队列是单向队列,同步队列是双向队列。

Fork/Join框架是Java7提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。Fork/Join框架要完成两件事情:

1.任务分割:首先Fork/Join框架需要把大的任务分割成足够小的子任务,如果子任务比较大的话还要对子任务进行继续分割

2.执行任务并合并结果:分割的子任务分别放到双端队列里,然后几个启动线程分别从双端队列里获取任务执行。子任务执行完的结果都放在另外一个队列里,启动一个线程从队列里取数据,然后合并这些数据。

在Java的Fork/Join框架中,使用两个类完成上述操作

1.ForkJoinTask:我们要使用Fork/Join框架,首先需要创建一个ForkJoin任务。该类提供了在任务中执行fork和join的机制。通常情况下我们不需要直接集成ForkJoinTask类,只需要继承它的子类,Fork/Join框架提供了两个子类:

a.RecursiveAction:用于没有返回结果的任务

b.RecursiveTask:用于有返回结果的任务

2.ForkJoinPool:ForkJoinTask需要通过ForkJoinPool来执行

任务分割出的子任务会添加到当前工作线程所维护的双端队列中,进入队列的头部。当一个工作线程的队列里暂时没有任务时,它会随机从其他工作线程的队列的尾部获取一个任务(工作窃取算法)。Fork/Join框架的实现原理ForkJoinPool由ForkJoinTask数组和ForkJoinWorkerThread数组组成,ForkJoinTask数组负责将存放程序提交给ForkJoinPool,而ForkJoinWorkerThread负责执行这

20、原子操作类

在java.util.concurrent.atomic包下,可以分为四种类型的原子更新类:原子更新基本类型、原子更新数组类型、原子更新引用和原子更新属性。

原子更新基本类型使用原子方式更新基本类型,共包括3个类:AtomicBoolean:原子更新布尔变量AtomicInteger:原子更新整型变量AtomicLong:原子更新长整型变量

原子更新数组通过原子更新数组里的某个元素,共有3个类:AtomicIntegerArray:原子更新整型数组的某个元素AtomicLongArray:原子更新长整型数组的某个元素AtomicReferenceArray:原子更新引用类型数组的某个元素AtomicIntegerArray常用的方法有:intaddAndSet(inti,intdelta):以原子方式将输入值与数组中索引为i的元素相加booleancompareAndSet(inti,intexpect,intupdate):如果当前值等于预期值,则以原子方式更新数组中索引为i的值为update值

原子更新引用类型AtomicReference:原子更新引用类型AtomicReferenceFieldUpdater:原子更新引用类型里的字段AtomicMarkableReference:原子更新带有标记位的引用类型。

原子更新字段类如果需要原子更新某个类的某个字段,就需要用到原子更新字段类,可以使用以下几个类:AtomicIntegerFieldUpdater:原子更新整型字段AtomicLongFieldUpdater:原子更新长整型字段AtomicStampedReference:原子更新带有版本号的引用类型。要想原子更新字段,需要两个步骤:每次必须使用newUpdater创建一个更新器,并且需要设置想要更新的类的字段更新类的字段(属性)必须为publicvolatile

21、同步屏障CyclicBarrier

CyclicBarrier的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。CyclicBarrier默认的构造方法是CyclicBarrier(intparties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。CyclicBarrier和CountDownLatch的区别

CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset()方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。CyclicBarrier还提供其他有用的方法,比如getNumberWaiting方法可以获得CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。比如以下代码执行完之后会返回true。

Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源Semaphore可以用于做流量控制,特别公用资源有限的应用场景,比如数据库连接。假如有一个需求,要读取几万个文件的数据,因为都是IO密集型任务,我们可以启动几十个线程并发的读取,但是如果读到内存后,还需要存储到数据库中,而数据库的连接数只有10个,这时我们必须控制只有十个线程同时获取数据库连接保存数据,否则会报错无法获取数据库连接。这个时候,我们就可以使用Semaphore来做流控,代码如下:

死锁产生的四个必要条件

互斥条件:资源是独占的且排他使用,进程互斥使用资源,即任意时刻一个资源只能给一个进程使用,其他进程若申请一个资源,而该资源被另一进程占有时,则申请者等待直到资源被占有者释放。不可剥夺条件:进程所获得的资源在未使用完毕之前,不被其他进程强行剥夺,而只能由获得该资源的进程资源释放。请求和保持条件:进程每次申请它所需要的一部分资源,在申请新的资源的同时,继续占用已分配到的资源。循环等待条件:在发生死锁时必然存在一个进程等待队列{P1,P2,…,Pn},其中P1等待P2占有的资源,P2等待P3占有的资源,…,Pn等待P1占有的资源,形成一个进程等待环路,环路中每一个进程所占有的资源同时被另一个申请,也就是前一个进程占有后一个进程所深情地资源。

解决死锁

一是死锁预防,就是不让上面的四个条件同时成立。二是,合理分配资源。三是使用银行家算法,如果该进程请求的资源操作系统剩余量可以满足,那么就分配。

有名管道(namedpipe):有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。

套接字(socket):套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。

中断

interrupt()的作用是中断本线程。本线程中断自己是被允许的;其它线程调用本线程的interrupt()方法时,会通过checkAccess()检查权限。这有可能抛出SecurityException异常。如果本线程是处于阻塞状态:调用线程的wait(),wait(long)或wait(long,int)会让它进入等待(阻塞)状态,或者调用线程的join(),join(long),join(long,int),sleep(long),sleep(long,int)也会让它进入阻塞状态。若线程在阻塞状态时,调用了它的interrupt()方法,那么它的“中断状态”会被清除并且会收到一个InterruptedException异常。例如,线程通过wait()进入阻塞状态,此时通过interrupt()中断该线程;调用interrupt()会立即将线程的中断标记设为“true”,但是由于线程处于阻塞状态,所以该“中断标记”会立即被清除为“false”,同时,会产生一个InterruptedException的异常。如果线程被阻塞在一个Selector选择器中,那么通过interrupt()中断它时;线程的中断标记会被设置为true,并且它会立即从选择操作中返回。如果不属于前面所说的情况,那么通过interrupt()中断线程时,它的中断标记会被设置为“true”。中断一个“已终止的线程”不会产生任何操作。

终止处于“阻塞状态”的线程通常,我们通过“中断”方式终止处于“阻塞状态”的线程。当线程由于被调用了sleep(),wait(),join()等方法而进入阻塞状态;若此时调用线程的interrupt()将线程的中断标记设为true。由于处于阻塞状态,中断标记会被清除,同时产生一个InterruptedException异常。将InterruptedException放在适当的为止就能终止线程,

终止处于“运行状态”的线程

interrupted()和isInterrupted()的区别

单例模式:懒汉式、饿汉式、双重校验锁、静态加载,内部类加载、枚举类加载。保证一个类仅有一个实例,并提供一个访问它的全局访问点。

代理模式:动态代理和静态代理,什么时候使用动态代理。

适配器模式:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

装饰者模式:动态给类加功能。

观察者模式:有时被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

外观模式:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

命令模式:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。

创建者模式:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

Set、List、Map的区别和联系

什么时候使用Hashmap

什么时候使用Linkedhashmap、Concurrenthashmap、Weakhashmap

哪些集合类是线程安全的

为什么Set、List、map不实现Cloneable和Serializable接口

Concurrenthashmap的实现,1.7和1.8的实现

Arrays.sort的实现

什么时候使用CopyOnArrayList

volatile的使用

synchronied的使用

reentrantlock的实现和Synchronied的区别

CAS的实现原理以及问题

AQS的实现原理

接口和抽象类的区别,什么时候使用

类加载机制的步骤,每一步做了什么,static和final修改的成员变量的加载时机

双亲委派模型

反射机制:反射动态擦除泛型、反射动态调用方法等

动态绑定:父类引用指向子类对象

JVM内存管理机制:有哪些区域,每个区域做了什么

JVM垃圾回收机制:垃圾回收算法垃圾回收器垃圾回收策略

jvm参数的设置和jvm调优

什么情况产生年轻代内存溢出、什么情况产生年老代内存溢出

内部类:静态内部类和匿名内部类的使用和区别

mysql索引的实现B+树的实现原理

什么情况索引不会命中,会造成全表扫描

java中bionioaio的区别和联系

为什么bio是阻塞的nio是非阻塞的nio是模型是什么样的

Reactor模型和Proactor模型

StringBuff和StringBuilder的实现,底层实现是通过byte数据,外加数组的拷贝来实现的

cas操作的使用

内存缓存和数据库的一致性同步实现

线程池的参数问题

ip问题如何判断ip是否在多个ip段中

判断数组两个中任意两个数之和是否为给定的值

乐观锁和悲观锁的实现

synchronized实现原理

你在项目中遇到的困难和怎么解决的

你在项目中完成的比较出色的亮点

消息队列广播模式和发布/订阅模式的区别

生产者消费者代码实现

死锁代码实现

线程池:参数,每个参数的作用,几种不同线程池的比较,阻塞队列的使用,拒绝策略

常见序列化协议及其优缺点

memcached内存原理,为什么是基于块的存储

搭建一个rpc需要准备什么

如果线上服务器频繁地出现fullgc,如何去排查

如果某一时刻线上机器突然量变得很大,服务扛不住了,怎么解决

LUR算法的实现

LinkedHashMap实现LRU

海量数据处理的解决思路

reactor模型的演变

阻塞、非阻塞、同步、异步区别

Collection的子接口

你觉得你的有点是什么,你的缺点是什么

netty底层实现,IO模型,ChannelPipeline的实现和原理

缓存的设计和优化

缓存和数据库一致性同步解决方案

你所在项目的系统架构,谈谈整体实现

消息队列的使用场景

ActiveMQ、RabbitMQ、Kafka的区别

1、String类为什么是final的。

2、HashMap的源码,实现原理,底层结构。

3、说说你知道的几个Java集合类:list、set、queue、map实现类咯。。。

4、描述一下ArrayList和LinkedList各自实现和区别

5、Java中的队列都有哪些,有什么区别。

6、反射中,Class.forName和classloader的区别

7、Java7、Java8的新特性(baidu问的,好BT)

8、Java数组和链表两种结构的操作效率,在哪些情况下(从开头开始,从结尾开始,从中间开始),哪些操作(插入,查找,删除)的效率高

9、Java内存泄露的问题调查定位:jmap,jstack的使用等等

10、string、stringbuilder、stringbuffer区别

11、hashtable和hashmap的区别

13、异常的结构,运行时异常和非运行时异常,各举个例子

14、Stringa=“abc”Stringb="abc"Stringc=newString("abc")Stringd="ab"+"c".他们之间用==比较的结果

15、String类的常用方法

16、Java的引用类型有哪几种

17、抽象类和接口的区别

18、java的基础类型和字节大小。

19、Hashtable,HashMap,ConcurrentHashMap底层实现原理与线程安全问题(建议熟悉jdk源码,才能从容应答)

20、如果不让你用JavaJdk提供的工具,你自己实现一个Map,你怎么做。说了好久,说了HashMap源代码,如果我做,就会借鉴HashMap的原理,说了一通HashMap实现

21、Hash冲突怎么办?哪些解决散列冲突的方法?

22、HashMap冲突很厉害,最差性能,你会怎么解决从O(n)提升到log(n)咯,用二叉排序树的思路说了一通

23、rehash

24、hashCode()与equals()生成算法、方法怎么重写

1、讲讲IO里面的常见类,字节流、字符流、接口、实现类、方法阻塞。

2、讲讲NIO。

3、String编码UTF-8和GBK的区别

4、什么时候使用字节流、什么时候使用字符流

5、递归读取文件夹下的文件,代码怎么实现

1、session和cookie的区别和联系,session的生命周期,多个服务部署时session管理。

5、无框架下配置web.xml的主要配置内容

6、jsp和servlet的区别

1、Java的内存模型以及GC算法

2、jvm性能调优都做了什么

3、介绍JVM中7个区域,然后把每个区域可能造成内存的溢出的情况说明

4、介绍GC和GCRoot不正常引用。

5、自己从classload加载方式,加载机制说开去,从程序运行时数据区,讲到内存分配,讲到String常量池,讲到JVM垃圾回收机制,算法,hotspot。反正就是各种扩展

6、jvm如何分配直接内存,new对象如何不分配在堆而是栈上,常量池解析

7、数组多大放在JVM老年代(不只是设置PretenureSizeThreshold,问通常多大,没做过一问便知)

8、老年代中数组的访问方式

9、GC算法,永久代对象如何GC,GC有环怎么处理

10、谁会被GC,什么时候GC

11、如果想不被GC怎么办

12、如果想在GC中生存1次怎么办

1、hibernate和ibatis的区别

2、讲讲mybatis的连接池。

3、spring框架中需要引用哪些jar包,以及这些jar包的用途

4.springMVC的原理

5、springMVC注解的意思

6、spring中beanFactory和ApplicationContext的联系和区别

7、spring注入的几种方式(循环注入)

8、spring如何实现事物管理的

9、springIOC

10、springAOP的原理

11、hibernate中的1级和2级缓存的使用方式以及区别原理(Lazy-Load的理解)

12、Hibernate的原理体系架构,五大核心接口,Hibernate对象的三种状态转换,事务管理。

1、Java创建线程之后,直接调用start()方法和run()的区别

2、常用的线程池模式以及不同线程池的使用场景

3、newFixedThreadPool此种线程池如果线程数达到最大值后会怎么办,底层原理。

5、了解可重入锁的含义,以及ReentrantLock和synchronized的区别

6、同步的数据结构,例如concurrentHashMap的源码理解以及内部实现原理,为什么他是同步的且效率高

7、atomicinteger和volatile等线程安全操作的关键字的理解和使用

8、线程间通信,wait和notify

9、定时线程的使用

10、场景:在一个主线程中,要求有大量(很多很多)子线程执行完之后,主线程才执行完成。多种方式,考虑效率。

11、进程和线程的区别

12、什么叫线程安全?举例说明

13、线程的几种状态

14、并发、同步的接口或方法

15、HashMap是否线程安全,为何不安全。ConcurrentHashMap,线程安全,为何安全。底层实现是怎么样的。

16、J.U.C下的常见类的使用。ThreadPool的深入考察;BlockingQueue的使用。(take,poll的区别,put,offer的区别);原子类的实现。

17、简单介绍下多线程的情况,从建立一个线程开始。然后怎么控制同步过程,多线程常用的方法和结构

18、volatile的理解

19、实现多线程有几种方式,多线程同步怎么做,说说几个线程里常用的方法

2、socket通信,以及长连接,分包,连接异常断开的处理。

3、socket通信模型的使用,AIO和NIO。

4、socket框架netty的使用,以及NIO的实现原理,为什么是异步非阻塞。

5、同步和异步,阻塞和非阻塞。

6、OSI七层模型,包括TCP,IP的一些基本知识

9、说说浏览器访问www.taobao.com,经历了怎样的过程。

10、HTTP协议、HTTPS协议,SSL协议及完整交互过程;

11、tcp的拥塞,快回传,ip的报文丢弃

13、head各个特点和区别

14、说说浏览器访问www.taobao.com,经历了怎样的过程。

1、MySql的存储引擎的不同

2、单个索引、联合索引、主键索引

3、Mysql怎么分表,以及分表后如果想按条件分页查询怎么办(如果不是按分表字段来查询的话,几乎效率低下,无解)

4、分表之后想让一个id多个表是自增的,效率实现

5、MySql的主从实时备份同步的配置,以及原理(从库读主库的binlog),读写分离

6、写SQL语句。。。

7、索引的数据结构,B+树

8、事务的四个特性,以及各自的特点(原子、隔离)等等,项目怎么解决这些问题

9、数据库的锁:行锁,表锁;乐观锁,悲观锁

10、数据库事务的几种粒度;

11、关系型和非关系型数据库区别

1、单例模式:饱汉、饿汉。以及饿汉中的延迟加载,双重检查

2、工厂模式、装饰者模式、观察者模式。

3、工厂方法模式的优点(低耦合、高内聚,开放封闭原则)

1、使用随机算法产生一个数,要求把1-1000W之间这些数全部生成。(考察高效率,解决产生冲突的问题)

2、两个有序数组的合并排序

3、一个数组的倒序

4、计算一个正整数的正平方根

6、二叉树的遍历算法

7、DFS,BFS算法

9、比较重要的数据结构,如链表,队列,栈的基本理解及大致实现。

10、排序算法与时空复杂度(快排为什么不稳定,为什么你的项目还在用)

11、逆波兰计算器

12、Hoffman编码

13、查找树与红黑树

1、有个每秒钟5k个请求,查询手机号所属地的笔试题(记得不完整,没列出),如何设计算法请求再多,比如5w,如何设计整个系统

2、高并发情况下,我们系统是如何支撑大量的请求的

3、集群如何同步会话状态

4、负载均衡的原理

5、如果有一个特别大的访问量,到数据库上,怎么做优化(DB设计,DBIO,SQL优化,Java优化)

6、如果出现大面积并发,在不增加服务器的基础上,如何解决服务器响应不及时问题“。

7、假如你的项目出现性能瓶颈了,你觉得可能会是哪些方面,怎么解决问题。

8、如何查找造成性能瓶颈出现的位置,是哪个位置照成性能瓶颈。

9、你的项目中使用过缓存机制吗?有没用用户非本地缓存

1、常用的linux下的命令

SPRING

Spring框架是一个为Java应用程序的开发提供了综合、广泛的基础性支持的Java平台。

Spring帮助开发者解决了开发中基础性的问题,使得开发人员可以专注于应用程序的开发。

Spring框架至今已集成了20多个模块。这些模块主要被分如下图所示的核心容器、数据访问/集成,、Web、AOP(面向切面编程)、工具、消息和测试模块。

下面列举了一些使用Spring框架带来的主要好处:

控制反转是应用于软件工程领域中的,在运行时被装配器对象来绑定耦合对象的一种编程技巧,对象之间耦合关系在编译时通常是未知的。在传统的编程方式中,业务逻辑的流程是由应用程序中的早已被设定好关联关系的对象来决定的。在使用控制反转的情况下,业务逻辑的流程是由对象关系图来决定的,该对象关系图由装配器负责实例化,这种实现方式还可以将对象之间的关联关系的定义抽象化。而绑定的过程是通过“依赖注入”实现的。

控制反转是一种以给予应用程序中目标组件更多控制为目的设计范式,并在我们的实际工作中起到了有效的作用。

依赖注入是在编译阶段尚未知所需的功能是来自哪个的类的情况下,将其他对象所依赖的功能对象实例化的模式。这就需要一种机制用来激活相应的组件以提供特定的功能,所以依赖注入是控制反转的基础。否则如果在组件不受框架控制的情况下,框架又怎么知道要创建哪个组件?

在Java中依然注入有以下三种实现方式:

Spring中的org.springframework.beans包和org.springframework.context包构成了Spring框架IoC容器的基础。

org.springframework.beans.factory.BeanFactory是SpringIoC容器的具体实现,用来包装和管理前面提到的各种bean。BeanFactory接口是SpringIoC容器的核心接口。

IOC:把对象的创建、初始化、销毁交给spring来管理,而不是由开发者控制,实现控制反转。

BeanFactory可以理解为含有bean集合的工厂类。BeanFactory包含了种bean的定义,以便在接收到客户端请求时将对应的bean实例化。

BeanFactory还能在实例化对象的时生成协作类之间的关系。此举将bean自身与bean客户端的配置中解放出来。BeanFactory还包含了bean生命周期的控制,调用客户端的初始化方法(initializationmethods)和销毁方法(destructionmethods)。

从表面上看,applicationcontext如同beanfactory一样具有bean定义、bean关联关系的设置,根据请求分发bean的功能。但applicationcontext在此基础上还提供了其他的功能。

以下是三种较常见的ApplicationContext实现方式:

1、ClassPathXmlApplicationContext:从classpath的XML配置文件中读取上下文,并生成上下文定义。应用程序上下文从程序环境变量中取得。

2、FileSystemXmlApplicationContext:由文件系统中的XML配置文件读取上下文。

3、XmlWebApplicationContext:由Web应用的XML文件读取上下文。

将Spring配置到应用开发中有以下三种方式:

在Spring框架中,依赖和服务需要在专门的配置文件来实现,我常用的XML格式的配置文件。这些配置文件的格式通常用开头,然后一系列的bean定义和专门的应用配置选项组成。

Spring的XML配置方式是使用被Spring命名空间的所支持的一系列的XML标签来实现的。Spring有以下主要的命名空间:context、beans、jdbc、tx、aop、mvc和aso。

如:

下面这个web.xml仅仅配置了DispatcherServlet,这件最简单的配置便能满足应用程序配置运行时组件的需求。

对于上面的@Beans配置文件相同的XML配置文件如下:

上述配置方式的实例化方式如下:利用AnnotationConfigApplicationContext类进行实例化

要使用组件组建扫描,仅需用@Configuration进行注解即可:

如果你要在你的web应用开发中选用上述的配置的方式的话,需要用AnnotationConfigWebApplicationContext类来读取配置文件,可以用来配置Spring的Servlet监听器ContextLoaderListener或者SpringMVC的DispatcherServlet。

注解装配在Spring中是默认关闭的。所以需要在Spring文件中配置一下才能使用基于注解的装配模式。如果你想要在你的应用程序中使用关于注解的方法的话,请参考如下的配置。

标签配置完成以后,就可以用注解的方式在Spring中向属性、方法和构造方法中自动装配变量。

下面是几种比较重要的注解类型:

Springbeanfactory负责管理在spring容器中被创建的bean的生命周期。Bean的生命周期由两组回调(callback)方法组成。

Spring框架提供了以下四种方式来管理bean的生命周期事件:

使用customInit()和customDestroy()方法管理bean生命周期的代码样例如下:

Spring容器中的bean可以分为5个范围。所有范围的名称都是自说明的,但是为了避免混淆,还是让我们来解释一下:

全局作用域与Servlet中的session作用域效果相同。

比如,在我们的应用程序中,一个Customer类引用了一个Person类,我们的要做的是创建一个Person的实例,然后在Customer内部使用。

Spring提供了以下四种集合类的配置元素:

下面看一下具体的例子:

第一种方法是使用如下面代码所示的标签:

也可用”util:”命名空间来从properties文件中创建出一个propertiesbean,然后利用setter方法注入bean的引用。

在Spring框架中,在配置文件中设定bean的依赖关系是一个很好的机制,Spring容器还可以自动装配合作关系bean之间的关联关系。这意味着Spring可以通过向BeanFactory中注入的方式自动搞定bean之间的依赖关系。自动装配可以设置在每个bean上,也可以设定在特定的bean上。

下面的XML配置文件表明了如何根据名称将一个bean设置为自动装配:

除了bean配置文件中提供的自动装配模式,还可以使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解之前需要在按照如下的配置方式在Spring配置文件进行配置才可以使用。

也可以通过在配置文件中配置AutowiredAnnotationBeanPostProcessor达到相同的效果。

配置好以后就可以使用@Autowired来标注了。

在Spring框架中共有5种自动装配,让我们逐一分析。

要使用@Autowired,需要注册AutowiredAnnotationBeanPostProcessor,可以有以下两种方式来实现:

1、引入配置文件中的下引入

需要用如下的方式使用来标明bean的设值方法。

RequiredAnnotationBeanPostProcessor是Spring中的后置处理用来验证被@Required注解的bean属性是否被正确的设置了。在使用RequiredAnnotationBeanPostProcesso来验证bean属性之前,首先要在IoC容器中对其进行注册:

但是如果没有属性被用@Required注解过的话,后置处理器会抛出一个BeanInitializationException异常。

@Autowired注解对自动装配何时何处被实现提供了更多细粒度的控制。@Autowired注解可以像@Required注解、构造器一样被用于在bean的设值方法上自动装配bean的属性,一个参数或者带有任意名称或带有多个参数的方法。

比如,可以在设值方法上使用@Autowired注解来替代配置文件中的元素。当Spring容器在setter方法上找到@Autowired注解时,会尝试用byType自动装配。

当然我们也可以在构造方法上使用@Autowired注解。带有@Autowired注解的构造方法意味着在创建一个bean时将会被自动装配,即便在配置文件中使用元素。

@Qualifier注解意味着可以在被标注bean的字段上可以自动装配。Qualifier注解可以用来取消Spring不能取消的bean应用。

下面的示例将会在Customer的person属性中自动装配person的值。

下面我们要在配置文件中来配置Person类。

Spring会知道要自动装配哪个personbean么?不会的,但是运行上面的示例时,会抛出下面的异常:

要解决上面的问题,需要使用@Quanlifier注解来告诉Spring容器要装配哪个bean:

请注意以下明显的区别:

Spring的ApplicationContext提供了支持事件和代码中监听器的功能。

我们可以创建bean用来监听在ApplicationContext中发布的事件。ApplicationEvent类和在ApplicationContext接口中处理的事件,如果一个bean实现了ApplicationListener接口,当一个ApplicationEvent被发布以后,bean会自动被通知。

Spring提供了以下5中标准的事件:

除了上面介绍的事件以外,还可以通过扩展ApplicationEvent类来开发自定义的事件。

为了监听这个事件,还需要创建一个监听器:

之后通过applicationContext接口的publishEvent()方法来发布自定义事件。

在FileSystemResource中需要给出spring-config.xml文件在你项目中的相对路径或者绝对路径。在ClassPathResource中spring会在ClassPath中自动搜寻配置文件,所以要把ClassPathResource文件放在ClassPath下。

如果将spring-config.xml保存在了src文件夹下的话,只需给出配置文件的名称即可,因为src文件夹是默认。

简而言之,ClassPathResource在环境变量中读取配置文件,FileSystemResource在配置文件中读取配置文件。

Spring框架中使用到了大量的设计模式,下面列举了比较有代表性的:

THE END
1.抖音热点推荐十大一元一分钟视频聊天软件让交流更加便捷同学的贵妇麻麻」|征服了同学的贵妇麻麻最新更,我需要灭火110秘密教学我需要灭火110秘密教学全文免费阅,麻花传媒沈芯语老师家访内幕曝光:麻花传媒沈芯语老师家访,《皇上当众进入太子NP主受》风行天下最新更新,皇上当众,皇上御花园hlh霍冶臻皇上御花园hlh霍冶臻全文免费阅读阅,《姊妹2》电影手机高清完整版在线观看-完整版-http://m.ouzhehua.com/v/video/20241122/62285033IUjet.shtml?20241205=YXubgWkF2-264903.scm
2.无需手机号登录的免费视频聊天软件有哪些无需手机号登录的免费视频聊天软件有哪些?一、引言随着互联网技术的快速发展,免费视频聊天软件逐渐成为了人们生活中不可或缺的一部分。对于一些希望在享受视频通话的同时又不想提供手机号的用户来说,这篇文章将为大家介绍一些无需手机号登录的免费视频聊天软件。二、详细介绍 1. 微信网页版 无需手机号登录的免费视频http://m.moshigongyuan.com/msgl/231825244.html
3.虚拟视频软件有哪些排行榜前十名玄关视讯通手机版是一款功能丰富的视频会议软件,用户可以使用软件进行工作会议的讨论,通过软件可以使用电子白板、云盘储存、英汉翻译、会议室等功能,能够增加会议的效率,使同事之间更好的沟通。 微信8.0.30版 微信8.0.30版是一个全新版本的交友互动软件,其中将此前许多功能都进行了一些优化,从而让聊天更加的轻松,在其中https://www.wj00.com/product/220780.html
4.字节跳动豆包电脑版上线视频生成功能,内测用户每日可免费生成十支内测页面显示,用户每日可免费生成十支视频。 据早期内测创作者介绍,当 PixelDance 生成 10 秒视频时,切换镜头 3-5 次的效果最佳,场景和角色能保持很好的一致性。此外,用户还可使用时序提示词、长镜头等技巧,增强视频的复杂度和表现力。 目前,基于该模型的视频生成能力已在豆包电脑版陆续开放。豆包相关负责人表示,https://m.163.com/dy/article/JJ4DRFNF05566WT8.html
5.PicoPico电脑版下载2024PicoPicoPC端最新版「含模拟器」模拟器导出视频apk文件 模拟器操作录制教程 网络异常修改DNS 双显卡切换独显 PicoPico电脑版介绍 PicoPico,一般又称picopico社交,picopico聊天软件。欢迎来到PicoPico在线声音社交乐园! 在PicoPico,没有孤独,只有陪伴。你可以在PicoPico分享快乐、欢笑、悲伤与烦恼,可以放下顾虑,敞开心扉,畅所欲言。 https://www.liqucn.com/pc/1215816.shtml
6.随机视频软件下载随机视频应用软件专题随机视频专题专题,为您提供随机视频聊天、随机视频网站、随机视频交友网站等内容。更多随机视频专题内容,请到华军软件园随机视频专题专题!https://m.onlinedown.net/zt/13155/
7.随机视频聊天的软件大全随机视频聊天的推荐下载PP助手为您提供随机视频聊天的软件有哪些大全推荐,在这里我们为您提供随机视频聊天的软件有哪些软件下载资源,随机视频聊天的软件有哪些安卓版本、官方版本&老版本下载地址合集,还可查阅相关随机视频聊天的软件有哪些攻略大全,欢迎到PP助手下载。https://wap.pp.cn/topic/483736/
8.推荐QQ密技60招!腾讯官方网站说是 普通号码资料空白里边好友无或者过少等等几条信息吧说是三个月不登陆腾讯有权收回号码也确实有号码被回收了是被什么收走了呢是被腾讯的专业扫号程序计算机给你扫走了密码都是16位的随机密码? 告诉你个秘密QQ永不怕回收 1.去疼讯主站下载个 英文版本 的QQ https://www.360doc.cn/article/84314_2001065.html
9.综述推荐十大一元一分钟视频聊天软件让交流更加便捷12月11日,只有孙子才会对爷爷提无理要求,天美传媒有限公司宣传片焕然一新,网友:耳目一新的风格让人,勾缠1V2江清砚夏朵PO最新章节列表勾缠1V2江清砚夏朵PO,《嫦娥仙子含精肉臀迎合》嫦娥仙子含精肉臀迎合最新章节列,《神话(胡歌版)》全集在线免费观看完整版-电视剧频道-四桶,怎样判断男生那方面行不行?五http://m.ruhrg.com/v/video/66734966Twsxz7.shtml?id=20241208cfsCa6.scm
10.关于西电计科本科学习的一些经验分享与资料汇总西电毕设拿良容易吗首先,选个好老师,不好一般体现在具有事贼多给分还抠、上课坐后排会被gank、随机签到、作业要求苛刻、改卷严、不捞人中的几个特征。此外,当时教我思修的花一个下午教拆电脑再装回去以及用光盘安装操作系统和一些系统软件,很简单,两人一组而且当时没验收,实验结束后几周内交报告,可以交电子版打印。报告见提取https://blog.csdn.net/zimuzi2019/article/details/132537657
11.信息与电脑(理论版)该方法利用数据随机化方法改变电子流的数据排列顺序,通过加密索引将重新排序的数据异构体转换为有秩序的密文,设定不同密码体制对电子流进行保序加密,完成云网络聊天室作为一种重要的通信方式,深受众多用户的喜爱。本文采用C/S模式,在Visual Studio 2010环境下结合SQL Server 2008数据库技术,设计并实现一种能实时http://xxdl.cbpt.cnki.net/WKE/WebPublication/wkTextContent.aspx?colType=4&yt=2020&st=22
12.最新修复版易支付源码全套+新增模板+无后门3.支付宝电脑网站支付兼容手机 2024/01/18:1.优化用户中心收入统计显示2.后台登录增加失败次数限制 2024/01/06:1.更新微信商家小票页面样式2.云闪付扫码支付支持直接跳转云闪付APP3.增加杉德、付呗支付插件 2023/12/19:1.更新PayPal、汇付、虎皮椒插件 2023/12/07:1.新增使用邀请码注册功能2.修复随机增减金额出现https://csym.xylzy.cn/196.html
13.几年前微信记录怎么样同步查询会用到的三种软件除了微信电脑版,iMyFone D-Back也是一款用户广泛使用的第三方数据恢复软件。它可以帮助用户恢复并提取微信聊天记录、照片、视频等数据。尤其是在更换手机或意外删除聊天记录时,iMyFone D-Back可以发挥重要作用,简单易用,适合一般用户。 使用iMyFone D-Back的过程也十分简单。用户只需将手机连接到电脑上,选择“恢复微信聊https://www.jianshu.com/p/c0b3a51e6ffc
14.和平精英电脑版下载超变打金传奇·打怪爆百万元宝·多召唤物合击→打金福利版 和平精英电脑官方正版是一款刺激的枪战射击类高容量弹鼓,火力持续性更强;引入全新弹道系统,每次射击时,都基于一个固定的散布框架,进行有限的随机1)增加聊天频道快速向好友发起组队预约的功能; 2)优化好友预约的回复体验; 7.个人信息处增加事件动态https://www.18183.com/down/3836734.html
15.电脑i3冰河银 / Windows 10 家庭版或Windows 11 家庭版随机 / i3|8GB|256GB / 官方标配 到货通知 预估到手价¥999起¥1499 预估到手价¥1899起¥2499 荣耀200 Pro 预估到手价¥2999起¥3499 ¥6999 预估到手价¥1999起¥2699 预估到手价¥949起¥999 https://www.hihonor.com/cn/shop/product/10086384201571.html
16.江湖如梦电脑版下载电脑玩江湖如梦模拟器创新阵法概念,随机应变自由布阵;阵眼英雄先手致胜,策略为王。反伤阵、奶妈阵、增伤阵千机迷阵,以弱胜强。 逍遥安卓模拟器电脑上,更为热门手游电脑版进行了专属的键盘按键设置,如王者荣耀LOL操控模式、和平精英专属绝地求生端游智能操控按键,支持一键批量多开,支持脚本辅助挂机群控,支持宏指令及手柄操控,电脑玩http://www.xyaz.cn/gc/apps-3586358-1.html
17.cf近身武器迷你深渊冰龙怎么获得穿越火线迷你深渊冰龙是什么东西穿越火线CG视频 (点击查看更多游戏cg视频) 穿越火线迷你深渊冰龙现在还能获得吗 可以获得,挑战地图-深渊冰龙之巢 评价获得:ss是给3个碎片,sss是给5个,有几率直接刷出了永久 活动获得:有时候活动会有送,可以关注下 。 1、cf如何刷冰龙刀 刷挑战模式。cf中的迷你深渊冰龙活动中的迷你深渊冰龙打一把有5个碎片,一https://www.773hf.com/wiki/26761.html
18.王者营地电脑版官方下载【其他】好友申请、聊天室等功能模块的体验得到了优化 请升级版本进行体验吧! 王者营地电脑版安装方法: 1.要在电脑上运行首先要安装一个安卓模拟器: http://www.xfdown.com/soft/41596.html 注意:xp用户需先安装Windows Installer 4.5和.net framework 2.0 http://www.xfdown.com/soft/124.html
19.电脑qq如何提取图片中的文字1、首先在电脑上登录QQ,随机进入好友聊天界面。2、然后找到需提取文字的图片,点击图片右键。3、点击提取图中文字选项,即可提取图中的文字了。 推荐度: 点击下载本文文档为doc格式 1 在电脑上登录QQ 首先在电脑上登录QQ,随机进入好友聊天界面。 2 找到需提取文字的图片 https://m.51dongshi.com/ezdshcsseg.html