多线程详解

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无锁机制实现的

什么是自旋锁?     内部不停的进行循环

相关文章
相关标签/搜索