Java中的多线程是一种抢占式的机制,而不是分时机制。抢占式的机制是有多个线程处于可运行状态,可是只有一个线程在运行。
● 共同点:
(1) 他们都是在多线程的环境下,均可以在程序的调用处阻塞指定的毫秒数,并返回。
(2) wait()和sleep()均可以经过interrupt()方法 打断线程的暂停状态 ,从而使线程马上抛出InterruptedException。
若是线程A但愿当即结束线程B,则能够对线程B对应的Thread实例调用interrupt方法。若是此刻线程B正在wait/sleep/join,则线程B会马上抛出InterruptedException,在catch() {} 中直接return便可安全地结束线程。
须要注意的是,InterruptedException是线程本身从内部抛出的,并非interrupt()方法抛出的。对某一线程调用 interrupt()时,若是该线程正在执行普通的代码,那么该线程根本就不会抛出InterruptedException。可是,一旦该线程进入到 wait()/sleep()/join()后,就会马上抛出InterruptedException 。
● 不一样点:
(1) 每一个对象都有一个锁来控制同步访问。Synchronized关键字能够和对象的锁交互,来实现线程的同步。
sleep方法没有释放锁,而wait方法释放了锁,使得其余线程可使用同步控制块或者方法。
(2) wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep能够在任何地方使用
(3) sleep必须捕获异常,而wait,notify和notifyAll不须要捕获异常
(4) sleep是线程类(Thread)的方法,致使此线程暂停执行指定时间,给执行机会给其余线程,可是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。
(5) wait是Object类的方法,对此对象调用wait方法致使本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备得到对象锁进入运行状态。java
1) 自旋锁, 自旋,jvm默认是10次吧,有jvm本身控制。for去争取锁.
2) 阻塞锁 被阻塞的线程,不会争夺锁.
3) 可重入锁 屡次进入改锁的域.
4) 读写锁.
5) 互斥锁 锁自己就是互斥的.
6) 悲观锁 不相信,这里会是安全的,必须所有上锁.
7) 乐观锁 相信,这里是安全的.
8) 公平锁 有优先级的锁.
9) 非公平锁 无优先级的锁.
10) 偏向锁 无竞争不锁,有竞争挂起,转为轻量锁.
11) 对象锁 锁住对象.
12) 线程锁.
13) 锁粗化 多锁变成一个,本身处理.
14) 轻量级锁 CAS实现.
15) 锁消除 偏向锁就是锁消除的一种.
16) 锁膨胀 jvm实现,锁粗化.
17) 信号量 使用阻塞锁 实现的一种策略.
18) 排它锁:X锁,若事务T对数据对象A加上X锁,则只容许T读取和修改A,其余任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。这就保证了其余事务在T释放A上的锁以前不能再读取和修改A。算法
结构型模式是描述如何将类对象结合在一块儿,造成一个更大的结构,结构模式描述两种不一样的东西:类与类的实例。故能够分为类结构模式和对象结构模式。
在GoF设计模式中,结构型模式有:
1) 适配器模式 Adapter
适配器模式是将一个类的接口转换成客户但愿的另一个接口。适配器模式使得本来因为接口不兼容而不能一块儿工做的那些类能够一块儿工做。
两个成熟的类须要通讯,可是接口不一样,因为开闭原则,咱们不能去修改这两个类的接口,因此就须要一个适配器来完成衔接过程。
2) 桥接模式 Bridge
桥接模式将抽象部分与它的实现部分分离,是它们均可以独立地变化。它很好的支持了开闭原则和组合锯和复用原则。实现系统可能有多角度分类,每一种分类都有可能变化,那么就把这些多角度分离出来让他们独立变化,减小他们之间的耦合。
3) 组合模式 Composite
组合模式将对象组合成树形结构以表示部分-总体的层次结构,组合模式使得用户对单个对象和组合对象的使用具备一致性。
4) 装饰模式 Decorator
装饰模式动态地给一个对象添加一些额外的职责,就增长功能来讲,它比生成子类更灵活。也能够这样说,装饰模式把复杂类中的核心职责和装饰功能区分开了,这样既简化了复杂类,有去除了相关类中重复的装饰逻辑。 装饰模式没有经过继承原有类来扩展功能,但却达到了同样的目的,并且比继承更加灵活,因此能够说装饰模式是继承关系的一种替代方案。
5) 外观模式 Facade
外观模式为子系统中的一组接口提供了赞成的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
外观模式中,客户对各个具体的子系统是不了解的,因此对这些子系统进行了封装,对外只提供了用户所明白的单一而简单的接口,用户直接使用这个接口就能够完成操做,而不用去理睬具体的过程,并且子系统的变化不会影响到用户,这样就作到了信息隐蔽。
6) 享元模式 Flyweight
享元模式为运用共享技术有效的支持大量细粒度的对象。由于它能够经过共享大幅度地减小单个实例的数目,避免了大量很是类似类的开销。
享元模式是一个类别的多个对象共享这个类别的一个对象,而不是各自再实例化各自的对象。这样就达到了节省内存的目的。
7) 代理模式 Proxy
为其余对象提供一种代理,并由代理对象控制对原对象的引用,以间接控制对原对象的访问。sql
1) Statement继承自Wrapper、PreparedStatement继承自Statement、CallableStatement继承自PreparedStatement。数据库
2) Statement接口提供了执行语句和获取结果的基本方法;
PreparedStatement接口添加了处理 IN 参数的方法;
CallableStatement接口添加了处理 OUT 参数的方法。
3) a.Statement: 普通的不带参的查询SQL; 支持批量更新, 批量删除;
b.PreparedStatement: 可变参数的SQL, 编译一次, 执行屡次, 效率高;
安全性好,有效防止Sql注入等问题;
支持批量更新, 批量删除;
c.CallableStatement: 继承自PreparedStatement, 支持带参数的SQL操做;
支持调用存储过程, 提供了对输出和输入/输出参数(INOUT)的支持;
Statement每次执行sql语句,数据库都要执行sql语句的编译, 最好用于仅执行一次查询并返回结果的情形,效率高于PreparedStatement。
4) PreparedStatement是预编译的,使用PreparedStatement有几个好处:: 设计模式
(1) 在执行可变参数的一条SQL时,PreparedStatement比Statement的效率高,由于DBMS预编译一条SQL固然会比屡次编译一条SQL的效率要高。
(2) 安全性好,有效防止Sql注入等问题。
(3) 对于屡次重复执行的语句,使用PreparedStament效率会更高一点,而且在这种状况下也比较适合使用batch;
(4) 代码的可读性和可维护性。缓存
-Xmx10240m -Xms10240m -Xmn5120m -XXSurvivorRatio=3
其最小内存值和Survivor区总大小分别是(10240m,2048m).安全
-Xmx:最大堆大小.
-Xms:初始堆大小.
-Xmn : 年轻代大小.
-XXSurvivorRatio:年轻代中Eden区与Survivor区的大小比值.
-Xms初始堆大小即最小内存值, 为10240m.
XXSurvivorRatio=3,即Eden:FromSurvivor:ToSurvivor=3:1:1;因此Survivor一共是2048m.网络
类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)7个阶段。其中准备、验证、解析3个部分统称为链接(Linking)。如图所示:数据结构
这里写图片描述:多线程
加载、验证、准备、初始化和卸载这5个阶段的顺序是肯定的,类的加载过程必须按照这种顺序循序渐进地开始,而解析阶段则不必定:它在某些状况下能够在初始化阶段以后再开始,这是为了支持Java语言的运行时绑定(也称为动态绑定或晚期绑定)。如下陈述的内容都已HotSpot为基准。
● 加载
在加载阶段(能够参考java.lang.ClassLoader的loadClass()方法),虚拟机须要完成如下3件事情:
1) 经过一个类的全限定名来获取定义此类的二进制字节流(并无指明要从一个Class文件中获取,能够从其余渠道,譬如:网络、动态生成、数据库等);
2) 将这个字节流所表明的静态存储结构转化为方法区的运行时数据结构;
3) 在内存中生成一个表明这个类的java.lang.Class对象,做为方法区这个类的各类数据的访问入口;
加载阶段和链接阶段(Linking)的部份内容(如一部分字节码文件格式验证动做)是交叉进行的,加载阶段还没有完成,链接阶段可能已经开始,但这些夹在加载阶段之中进行的动做,仍然属于链接阶段的内容,这两个阶段的开始时间仍然保持着固定的前后顺序。
● 验证
验证是链接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,而且不会危害虚拟机自身的安全。
验证阶段大体会完成4个阶段的检验动做:
1) 文件格式验证:验证字节流是否符合Class文件格式的规范;例如:是否以魔术0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围以内、常量池中的常量是否有不被支持的类型。
2) 元数据验证:对字节码描述的信息进行语义分析(注意:对比javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求;例如:这个类是否有父类,除了java.lang.Object以外。
3) 字节码验证:经过数据流和控制流分析,肯定程序语义是合法的、符合逻辑的。
4) 符号引用验证:确保解析动做能正确执行。
验证阶段是很是重要的,但不是必须的,它对程序运行期没有影响,若是所引用的类通过反复验证,那么能够考虑采用-Xverifynone参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。
● 准备
准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。这时候进行内存分配的仅包括类变量(被static修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一块儿分配在堆中。其次,这里所说的初始值“一般状况”下是数据类型的零值,假设一个类变量的定义为:
public static int value=123;
那变量value在准备阶段事后的初始值为0而不是123. 由于这时候还没有开始执行任何java方法,而把value赋值为123的putstatic指令是程序被编译后,存放于类构造器()方法之中,因此把value赋值为123的动做将在初始化阶段才会执行。
至于“特殊状况”是指:public static final int value=123,即当类字段的字段属性是ConstantValue时,会在准备阶段初始化为指定的值,因此标注为final以后,value的值在准备阶段初始化为123而非0.
● 解析
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。解析动做主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。
● 初始化
类初始化阶段是类加载过程的最后一步,到了初始化阶段,才真正开始执行类中定义的java程序代码。在准备极端,变量已经付过一次系统要求的初始值,而在初始化阶段,则根据程序猿经过程序制定的主管计划去初始化类变量和其余资源,或者说:初始化阶段是执行类构造器<clinit>()方法的过程.
<clinit>()方法是由编译器自动收集类中的全部类变量的赋值动做和静态语句块static{}中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序所决定的,静态语句块只能访问到定义在静态语句块以前的变量,定义在它以后的变量,在前面的静态语句块能够赋值,可是不能访问。以下:
public class Test { static { i=0; System.out.println(i);//这句编译器会报错:Cannot reference a field before it is defined(非法向前应用) } static int i=1; }
更多介绍,请移步:http://blog.csdn.net/u013256816/article/details/50829596
大多数 JVM 将内存区域划分为: Method Area(Non-Heap)(方法区), Heap(堆), Program Counter Register(程序计数器), VM Stack(虚拟机栈,也有翻译成JAVA 方法栈的), Native Method Stack ( 本地方法栈 ),其中Method Area 和 Heap 是线程共享的 ,VM Stack,Native Method Stack 和Program Counter Register 是非线程共享的。
为何分为线程共享和非线程共享的呢?
首先咱们熟悉一下一个通常性的 Java 程序的工做过程。一个 Java 源程序文件,会被编译为字节码文件(以 class 为扩展名),每一个java程序都须要运行在本身的JVM上,而后告知 JVM 程序的运行入口,再被 JVM 经过字节码解释器加载运行。
那么程序开始运行后,都是如何涉及到各内存区域的呢?
归纳地说来,JVM初始运行的时候都会分配好 Method Area(方法区) 和Heap(堆) ,而JVM 每遇到一个线程,就为其分配一个 Program Counter Register(程序计数器) , VM Stack(虚拟机栈)和Native Method Stack (本地方法栈), 当线程终止时,三者(虚拟机栈,本地方法栈和程序计数器)所占用的内存空间也会被释放掉。这也是为何我把内存区域分为线程共享和非线程共享的缘由,非线程共享的那三个区域的生命周期与所属线程相同,而线程共享的区域与JAVA程序运行的生命周期相同,因此这也是系统垃圾回收的场所只发生在线程共享的区域(实际上对大部分虚拟机来讲知发生在Heap上)的缘由。
方法区在JVM中也是一个很是重要的区域,它与堆同样,是被线程共享的区域。 在方法区中,存储了每一个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等。
程序计数器是Java虚拟机中惟一一个没有规定任何内存溢出OutOfMemoryError的内存区域,Java虚拟机中的程序计数器指向正在执行的字节码地址,而不是下一条。
两个最基本的Java垃圾回收算法:复制算法和标记清理算法。
复制算法:两个区域A和B,初始对象在A,继续存活的对象被转移到B。此为新生代最经常使用的算法。
标记清理:一块区域,标记要回收的对象,而后回收,必定会出现碎片,那么引出:标记-整理算法:多了碎片整理,整理出更大的内存放更大的对象。
两个概念:新生代和年老代。
新生代:初始对象,生命周期短的。
永久代:长时间存在的对象。
整个java的垃圾回收是新生代和年老代的协做,这种叫作分代回收。
P.S:Serial New收集器是针对新生代的收集器,采用的是复制算法。
Parallel New(并行)收集器,新生代采用复制算法,老年代采用标记整理。
Parallel Scavenge(并行)收集器,针对新生代,采用复制收集算法。
Serial Old(串行)收集器,新生代采用复制,老年代采用标记清理。
Parallel Old(并行)收集器,针对老年代,标记整理。
CMS收集器,基于标记清理。
G1收集器:总体上是基于标记清理,局部采用复制。
综上:新生代基本采用复制算法,老年代采用标记整理算法。cms采用标记清理。
重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。
若是在子类中定义某方法与其父类有相同的名称和参数,咱们说该方法被重写 (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。
若是在一个类中定义了多个同名的方法,它们或有不一样的参数个数或有不一样的参数类型,则称为方法的重载(Overloading)。
Overloaded的方法是能够改变返回值的类型。
1) 尽可能使用many-to-one,避免使用单项one-to-many;
2) 灵活使用单向one-to-many;
3) 不用一对一,使用多对一代替一对一;
4) 配置对象缓存,不使用集合缓存;
5) 一对多使用Bag 多对一使用Set;
6) 继承使用显示多态 HQL:from object polymorphism="exlicit" 避免查出全部对象;
7) 消除大表,使用二级缓存。