MYSQL基础详解:https://www.cnblogs.com/itchang/p/5784863.html
事物隔离性详解:https://www.cnblogs.com/fjdingsd/p/5273008.html
阿里JAVA开发手册:http://kangroo.gitee.io/ajcg/#/naming-style
Java关键字final、static使用总结:http://blog.51cto.com/lavasoft/18771html
--------------------------------------------------------------------------------------------------
多线程
进程:进程是线程的集合,正在运行的应用程序。
线程:线程是一条执行路径,一个独立的执行单元。
多线程做用:调高程序效率。
建立线程的方法:
1:集成Thread类
2:实现Runnable接口
3:匿名内部类
4:callable
5:线程池
同步:代码从上往下执行,又称:单线程
异步:每一个线程之间互不影响,又称:多线程
守护线程:和主线程,GC线程一块儿销毁
非守护线程:主线程销毁了,仍是会继续执行的
进程中包括了,主线程,GC线程,用户线程(用户本身建立的线程,非守护线程)
多线程运行状态:新建状态 - 就绪状态 - 运行状态 - 阻塞状态 - 死亡状态
多线程运行状态流程图:http://img.blog.csdn.net/20161017181631639?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
线程安全问题:当多个线程共享同一个全局、静态变量,作写操做时,可能会受到其余线程的干扰,致使数据冲突的问题呢
解决线程安全问题:
1:同步synchroized -- 自动释放
2:锁(locak) -- 手动释放
为何使用同步或者锁能解决线程安全问题?
多个线程共享同一个全局、静态变量时,只让一个线程的代码执行,代码执行完毕后释放锁,在让其余线程执行。
这里须要注意一下,
同步和线程同步不是一个概念
程序中的同步是单线程的,代码从上往下执行
线程同步是保证线程安全
同步synchroized执行方法
1:同步代码块 -- 使用的是对象锁
synchroized(锁){}
2:同步函数 -- 使用的是this锁
public synchroized void add(){}
3: 静态同步函数 -- 使用的是当前字节码文件锁(类名.class)
public static synchroized void add(){}java
注意:在多线程的同步中使用的不是同一把锁,那么线程仍是不安全的git
同步synchroized必须有的条件
1:必需要有两个线程以上,须要发生同步
2:多个线程想同步,必须用同一把锁
3:保证只有一个线程进行执行算法
同步synchroized原理
1:有一个线程已经拿到锁了,其余线程会一直等待,直到线程释放了锁,其余线程将会抢这把锁,抢到锁的线程将会执行代码。
同步synchroized缺点:效率低
死锁:同步中嵌套同步,没法释放,一直等待,变成死锁。数据库
多线程三大特性
原子性:在操做中要么都执行,要么都不执行,保证数据一致
可见性:java内存模型,一个线程修改了共享变量值,其余线程能过当即得知这个修改后的值
有序性:程序执行的顺序按照代码的前后顺序执行数组
java内存模型(JMM):一个线程对共享变量写入是,能对别的线程可见
流程图:https://sfault-image.b0.upaiyun.com/140/667/1406676357-594a0dc7e13e8_articlex
java内存模式
主内存:主要存放共享全局变量
私有本地内存(工做内存):本地线程私有变量缓存
看流程图就知道为何数据会不可见了。
线程1从主内存中获取到共享变量(A)到工做内存1中,而后在修改共享变量(A)的值,在修改期间,线程2从主内存中获取到共享变量(A)到工做内存2中(这里须要注意的是,线程1还没修改值,线程2获取到的是旧的值),线程1修改完后将共享变量(A)传递给主内存中,这就发生了可见行的问题。
加上volatile就能够解决可见性问题:private static volatile int A;安全
volatile的做用:保证线程之间可见性,不保存原子性
AtomicInteger的做用:保证原子性
多线程通信方式:https://static.oschina.net/uploads/space/2018/0125/120221_Ronq_3578766.png多线程
wait():让当前线程从运行状态变成休眠状态,释放锁的资源
notify(): 让单钱线程从休眠的状态变成运行状态
注意,在同步中才能使用wait()、notify()
join():等待主线程执行完毕
Lock锁
Lock锁的写法
Lock lock = new ReentrantLock();
lock.lock();
try{
//可能会出现线程安全的操做
}finally{
//必定在finally中释放锁
//也不能把获取锁在try中进行,由于有可能在获取锁的时候抛出异常
lock.ublock();
}并发
Lock锁与synchronized同步锁的区别
lock手动锁
synchronized同步自动锁
Condition用法
Condition的功能相似于在传统的线程技术中的,Object.wait()和Object.notify()的功能。
线程安全的类
Vector和ArrayList区别
实现原理都是经过数据实现,查询速度快,增长,修改,删除速度慢
区别:线程安全问题
Vector是安全(上锁的集合),ArrayList线程不安全
ArrayList效率高
Hashtable和HasMap集合
Hashtable线程是安全
HasMap线程是不安全
链表+数组 put Hascode取模获得下标位置 一致性取模算法
证实:Hashtable是线程安全?查看源码的put方法
JDK并发包
前言:
在JDK1.5以后,发明一种新并发包
JDK1.5以后,产生了不少java并发包
Hashtable线程是安全,效率很是低,锁的资源竞争。
多线程共享同一个hashtable 加锁、影响效率、每次只能有个线程去操做hashtable
并发安全类
ConcurrenHashMap -- 并发包
分段锁 默认16段
将一个总体(集合)拆分红多个小的Hashtable,默认分红16段
这样就能够有效的减小锁的资源竞争
CountDownLatch --计数用的
CyclicBarrier --计数用的
并发队列 --生产者消费者概念
在并发队列中分有界、无界
有界、无界的区别
为防止理解不深,先引用一个问题
数组和集合的区别
数组是有长度限制的、集合是没有长度限制的
同等
有界是有限制的,无界是无限制的
阻塞队列、非阻塞队列 --这里要注意是阻塞'队列'
区别:
生产者写入满的时候,就会进入到阻塞。
当队列为空的时候,消费者也会进入阻塞。
队列遵循的规则
先进先出
后进后出
ConcurrentLinkedDeque和BlockingQueue的区别:
BlockingQueue能够阻塞,有界。
ConcurrentLinkedDeque不可阻塞,无界。
多线程
什么是线程池
Java中的线程池是运用场景最多的并发框架,几乎全部须要异步或并发执行任务的程序
均可以使用线程池。在开发过程当中,合理地使用线程池可以带来3个好处。
第一:下降资源消耗。经过重复利用已建立的线程下降线程建立和销毁形成的消耗。
第二:提升响应速度。当任务到达时,任务能够不须要等到线程建立就能当即执行。
第三:提升线程的可管理性。线程是稀缺资源,若是无限制地建立,不只会消耗系统资源,
还会下降系统的稳定性,使用线程池能够进行统一分配、调优和监控。可是,要作到合理利用
线程池,必须对其实现原理了如指掌。
线程池做用
线程池是为忽然大量爆发的线程设计的,经过有限的几个固定线程为大量的操做服务,减小了建立和销毁线程所需的时间,从而提升效率。
若是一个线程的时间很是长,就不必用线程池了(不是不能做长时间操做,而是不宜。),何况咱们还不能控制线程池中线程的开始、挂起、和停止。
在线程池中 ThreadPoolExecutor 是核心类
线程池四种建立方式
Executor封装了四种线程池类型
Java经过Executors(jdk1.5并发包)提供四种线程池,分别为:
1,newCachedThreadPool建立一个可缓存线程池,若是线程池长度超过处理须要,可灵活回收空闲线程,若无可回收,则新建线程。
2,newFixedThreadPool 建立一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
3,newScheduledThreadPool 建立一个定长线程池,支持定时及周期性任务执行。
4,newSingleThreadExecutor 建立一个单线程化的线程池,它只会用惟一的工做线程来执行任务,保证全部任务按照指定顺序(FIFO, LIFO, 优先级)执行。
java中线程池 核心使用的构造函数 采用ThreadPoolExecutor
ThreadPoolExecutor构造函数参数
corePoolSize: 核心池的大小
maximumPoolSize: 线程池最大线程数
keepAliveTime: 终止时间
unit: 超时秒数
线程池原理
线程池原理剖析
提交一个任务到线程池中,线程池的处理流程以下:
一、判断线程池里的核心线程是否都在执行任务,若是不是(核心线程空闲或者还有核心线程没有被建立)则建立一个新的工做线程来执行任务。若是核心线程都在执行任务,则进入下个流程。
二、线程池判断工做队列是否已满,若是工做队列没有满,则将新提交的任务存储在这个工做队列里。若是工做队列满了,则进入下个流程。
三、判断线程池里的线程是否都处于工做状态,若是没有,则建立一个新的工做线程来执行任务。若是已经满了,则交给饱和策略来处理这个任务。
线程池 合理配置 --
CPU密集 : 线程数和CPU数相同
CPU使用频繁就使用
IO密集:2*CPU核数
操做数据库,IO须要等待,线程都须要等待,阻塞
CPU密集和IO密集的区别
IO密集常常会有阻塞,休眠,CPU密集会频繁的调用
java锁机制
悲观锁
乐观锁
分段锁
重入锁
读写锁
CAS无锁
自旋锁
排它锁
案例:
买水果案例
小明买了10块水果,给了老板钱。然而小红不知道小明给了钱,小红又给了老板10块。(数据重复)
在“多数据源”的状况下(2个或者2个以上的JDBC链接)就要使用锁
什么是悲观锁?
默认加排它锁
每次在拿数据的时候,都会上锁。
悲观锁:悲观锁悲观的认为每一次操做都会形成更新丢失问题,在每次查询时加上排他锁。
每次去拿数据的时候都认为别人会修改,因此每次在拿数据的时候都会上锁,这样别人想拿 这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了不少这种锁机制,好比 行锁,表锁等,读锁,写锁等,都是在作操做以前先上锁。
使用方法:
SQL语句后面添加 for update
例子:
select * from order for update
原理:
只容许有一个链接进行操做,当一个线程进入后会锁住,别的线程要等待锁释放才能使用
缺点:
效率低 --由于只能保证一个链接进行操做
什么是乐观锁?
版本控制
乐观锁:乐观锁会乐观的认为每次查询都不会形成更新丢失,利用版本字段控制
原理:
首先数据库中有个版本号(version),2个数据源同时操做SQL语句,第一个操做的时候version是0,而后会把version+1(版本号+1),那么第二个操做的时候查询version=0的数据是没有的,查不到的,最后判断影响行数就能够了,假如影响行数>0就能够进行操做
悲观锁和乐观锁的区别
若是查询量小,可使用悲观锁
使用版本控制操做,使用乐观锁
什么是重入锁?
重入锁(ReentrantLock 和synchronized) 与 非重入锁(死锁) 递归使用同步
什么是读写锁?
两个线程同时读一个资源没有任何问题,因此应该容许多个线程能在同时读取共享资源。可是若是有一个线程想去写这些共享资源,就不该该再有其它线程对该资源进行读或写(译者注:也就是说:读-读能共存,读-写不能共存,写-写不能共存)
什么是CAS无锁?
原子类底层如何实现保证线程安全,CAS无所机制效率比有所机制搞。
CAS无所机制其实和乐观锁概念相似
CAS体系中有三个参数
它包含三个参数CAS(V,E,N): V表示要更新的变量,E表示预期值,N表示新值。仅当V值等于E值时,才会将V的值设为N,若是V值和E值不一样,则说明已经有其余线程作了更新,则当前线程什么都不作。最后,CAS返回当前V的真实值。
实现过程:
当V=E表示没有任何线程操做,那么N值改成V值,返回N
但V!=E表示有线程操做过,那么N值改成E值,返回V
例子:
AtomicInteger就是CAS无锁机制实现的
什么是自旋锁? 内部不停的进行循环