JAVA高效并发

in 编程
关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9

JAVA内存模型

  • 主内存:物理内存中划分给JVM的内存(堆内存:线程共享);
  • 工作内存:线程(栈内存,线程私有)使用的主内存的副本拷贝,线程对变量的所有操作(读、写)必须在工作内存中进行;不同线程之间工作内存不共享,二者之间的值传递,必须通过主内存来完成;

 

JAVA内存模型规定的工作内存和主内存之间交互的的八个操作

  • Lock:加锁,作用于主内存,执行之后,线程独占;
  • Unlock:解锁,作用于主内存,和Lock成对出现,Loak一次,就得Unlock一次,而且必须是同一个线程操作;
  • Read:读取,作用于主内存,把变量传输到线程的工作内存;
  • Load:载入,和Read成对出现,而且只能在Read之后执行;
  • Use:使用
  • Assign:赋值,执行之后,必须执行Store操作,不能丢弃Assign之后的值;
  • Store:存储,把工作内存的变量传递到主内存;
  • write:写入,和Store成对出现,而且只能在Store之后执行;

 

JAVA内存模型的特征

  • 原子性:read、load、usr、assign、store、write、synchronized(lock、unlock)
  • 可见性:final、volatile
  • 有序性:如果在本地线程中观察,所有的操作都是有序的(线程内表现为串行);如果在一个线程中观察另一个线程,所有的操作都是无序的(指令重排、工作内存和主内存存在同步延迟);

 

线程的实现

  • 使用内核线程实现;
  • 使用用户线程实现;
  • 混合实现;

JAVA在jdk1.2之前,是基于“绿色线程”的用户线程实现,之后改为基于操作系统原生线程模型实现;也就是说,依赖于当前的操作系统实现;

当前windows、linux都使用一对一对线程模型来实现,一条JAVA线程就映射到一条轻量级进程中(synchronized慢的原因:线程的阻塞和唤醒都需要操作系统帮忙,需要从用户态转换到核心态,切换需要耗费很多的处理器时间);

 

JAVA线程调度方式

  • 协同式:一个线程执行完之后,告诉操作系统,操作系统会把这个处理器分配给另一个线程;
  • 抢占式:线程是否能够获得处理器资源,有操作系统来决定;JAVA使用的是抢占式;

 

JAVA定义了5中线程状态

  • 新建:刚创建,但是未启动;
  • 运行:正在运行,或者等待操作系统分配资源;
  • 限时等待:设置了等待时间,时间到了以后就可以由操作系统来唤起;
  • 无限时等待:没有设置等待时间,除非有其他进程显式的唤起,否则一直处于这个状态;
  • 阻塞:在获取排它锁时,如果获取不到,则进入阻塞状态;
  • 结束

 

线程安全分类

  • 不可变:对象的状态在初始化之后,是不可更改的,绝对安全;
  • 绝对线程安全:无论环境如何,调用者都无需做任何同步操作,就可以保证对象的安全使用;
  • 相对线程安全:保证对一个对象做单独操作是线程安全的,不需要调用者主动去保证其安全(排除一些特定顺序的连续调用);
  • 线程兼容:调用者通过额外的同步手段,保证对象在并发环境中对安全使用(通过给方法加同步锁等);
  • 线程对立:无论调用者无论做什么操作,都无法在多线程环境中并发使用代码;

 

手动同步方式(线程兼容)

  1. Synchronized:JAVA自己实现的重量级锁;
  2. ReentrantLock:JUC包中提供的一个可调用的API,需要调用者自己调用lock、unlock方法;

 

线程安全的实现方式

  1. 互斥同步;
    1. 通过锁实现;
    2. 也叫阻塞同步;
    3. 属于悲观的并发策略
  2. 非阻塞同步
    1. 基于冲突检测,发现冲突,则重试,直到成功为止;
    2. 使用CAS操作完成;JAVA中有Unsafe实现,但是不开放给用户使用,是本地方法;
    3. CAS无法处理ABA问题;
  3. 无同步方案
    1. 对于可重入代码,可以不关心是否需要同步,比如方法的参数只来源于调用者,并且参数一样的情况下,返回值也一定一样;
    2. 线程本地存储:如果共享数据的代码,必定在一个线程中执行,那么不需要加同步操作;为了利用这种情况,可以使用ThreadLocal来存储线程,和对应的线程本地变量;

 

synchronized:

把代码块声明为 synchronized,有两个重要后果,通常是指该代码具有 原子性(atomicity)和 可见性(visibility)

 

  1. synchronized 加在示例方法上,锁是该示例;加在类方法上,锁是该类;
  2. synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。用法是: synchronized(this){},它的作用域是当前对象;
  3. 线程同步的目的是为了保护多个线程访问相同的资源时对资源的破坏(造成资源过期,脏读更好理解);
  4. 死锁是线程间相互等待锁锁造成的,在实际中发生的概率非常的小,一旦程序发生死锁,如果任何一方都不放弃,程序将死掉;
  5. 内部类的同步是独立于外部类的;
  6. synchronzied进行同步的时候,真正被同步的是在不同线程中表示被锁定对象的内存块,使得线程中的对象缓存和内存中锁定的内存保持相同;

 

ReentrantLock:

  1. java.util.concurrent.lock 中的 Lock 框架是锁定的一个抽象,它允许把锁定的实现作为 Java 类,而不是作为语言的特性来实现;
  2. 拥有与 synchronized 相同的并发性和内存语义,但是添加了类似轮询锁(自旋锁)、等待可中断锁、锁可以绑定多个条件(Condition对象)的特性;
  3. lock 必须在 finally 块中释放;
  4. ReentrantLock 构造器的一个参数是 boolean 值 fair,表示获取锁是否公平,默认false,不公平锁则允许直接获取锁;

 

volatile(准确的应该叫读锁):

  1. 底层实现:多线程时,每个线程对工作内存都会有该变量的副本,如果一个线程修改了自己的副本,会同时通知(lock指令)其他线程,让其他线程中的副本失效,在其他线程使用自己的副本时,发现是失效的,会从主内存重新读取一次;
  2. Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性;
  3. 多线程中,使用Volatile 变量时,都会从主内存中读取,而不是从线程的工作内存中读缓存的值,所以可以保证取到的值是最新的;
  4. 要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:

对变量的写操作不依赖于当前值(原子操作);a++ 和 a=2 的区别;

该变量没有包含在具有其他变量的不变式中;

  1. 锁一次只允许一个线程访问值,volatile 允许多个线程执行读操作;

 

锁优化

  • 锁粗化:如果在一个细小的操作上加了锁,而且被同一个线程连续的调用,那么虚拟机会把锁的范围扩大,把调用的操作也包含到这个锁定的范围内,这样做可以减少加锁-解锁的次数;
  • 锁消除:在运行期间,虚拟机检测到加了同步锁,但是不可能存在共享数据数据竞争,虚拟机在即时编译时,会去掉该锁;
  • 锁膨胀:如果虚拟机开启了偏向锁、轻量级锁,虚拟机会先尝试优先使用轻量级锁,如果发现有多个线程都在争取这个锁,锁会升级为重量级锁,也就是互斥锁;
  • 轻量级锁:在一个线程获取一个对象锁时,如果能获取到,会将自己的线程ID存放到对象头信息中,同时将对象的Mark Word拷贝到线程的帧栈中(锁记录),更新对象的说状态为轻量级锁(01),这时候实际是没有互斥锁的;如果在这个过程中,又有其他线程进来,就会出现锁升级;释放锁也一样,锁记录和线程ID就类似于对象锁的版本号,成功获取到之后,会拿着这个版本号取解锁,版本号一致才能解锁;
  • 偏向锁:一个对象锁在第一次被一个线程获取时,记录该线程ID,之后,如果每次都是这个线程来获取锁,那么虚拟机将不进行任何同步操作,直接执行目标代码;如果有第二个线程获取了该对象锁,那么之后就不会有偏向锁了;

 

备注:

自旋锁:

互斥同步对性能最大的影响是阻塞的实现,挂起线程和回复线程的操作都需要转入内核态中完成,这些操作对系统性能影响很大。实际情况是,共享数据的锁定状态只会持续很短的时间,在获取锁时,如果没有获取到,根据实际的运行情况,稍等一会儿,但是不放弃处理器的执行时间,可能就可以获取到了,这个“稍等”,可以让线程执行一个忙循环(自旋),这就是所谓的自旋锁。

关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9
扫一扫关注公众号添加购物返利助手,领红包
Comments are closed.

推荐使用阿里云服务器

超多优惠券

服务器最低一折,一年不到100!

朕已阅去看看