java并发(6)

一、为何会有并发问题

竞争条件:当多于2个程序访问试图读写同一个数据时,会因2个程序的执行顺序影响各自的执行结果,这样的情况叫做竞争条件。就叫有并发问题。

线程安全:当多个线程访问一个对象时,如果我们不需要额外的考虑这些线程在运行时的调度和交替,且不需要额外的同步机制,程序都能运行正确的结果,那么称对象是线程安全的

java内存模型和协议

内存模型

操作系统硬件的并发问题:多个处理器都操作一个内存数据。
这里写图片描述

对应我们的java程序中:多个线程针对堆中的数据读取存在竞争条件
这里写图片描述

另外,cpu中对指令的优化和java程序中git编译器的优化,会出现指令重排序的问题。

内存访问协议

java把线程对数据的操作协议概述为8个操作:

  • read:作用于主内存,把主内存的数据读取到工作内存中
  • load:作用于工作内存,把read得到的数据放到工作内存的变量副本中
  • use:作用于工作内存,把工作内存中的一个变量的值传给执行引擎
  • assign:作用于工作内存,把从执行引擎中获取的值传赋值给工作内存中的变量
  • store:作用于工作内存,把工作内存中的值传递给主内存
  • write:作用于主内存,把store的值写到主内存中
  • lock:只用于主内存,把一个变量标志位线程独占状态
  • unlock:只用于主内存,释放线程的独占状态

上述操作为原子性操作,由各个虚拟机实现。
虚拟机规定了一些规则,能够保证一些内存操作是线程安全的。等同于先行并发原则,java中自带的先行并发,可以保证一般的程序的编写。

volatile规则

volatile是一组特定的规则,是最轻量级的同步机制。
规则:
1、每次使用变量前,都要重新加载变量的值
2、每次更新变量,都会立马更新到主存中
3、被修饰的变量不可被指令重排序
有2个作用:1、可见性 2、禁止指令重排序

使用场景:当满足特定场景时,优先使用

二、基本原则

为解决上述问题,设计3个基本原则:

  • 原子性 :由JMM模型保证read,load,use,assign,store,write原子性 更大的原子性则要sync保证
  • 可见性 :变量的修改对其他线程可见 volatile 和sync final
  • 有序性:本线程 串行的语义,指令重排序 由volatile和sync保证

三、线程的实现和状态

线程的实现,3种方式

  • 一对一的内核线程或者一对一的轻量级进程
  • 用户线程
  • 2个的mix
    java在window和linux中都是使用的一对一的轻量级进程,受到操作系统的线程数的限制。

线程的状态

这里写图片描述

  • 开始
  • 运行中
  • 等待
  • 限时等待
  • 阻塞
  • 结束

四、java线程安全的方法

互斥同步,悲观锁的概念

1、sync关键字
内部字节码由monitorenter和monitorexit实现,是可重入锁
调用会导致线程阻塞,需要切入到内核态调度,可通过锁自旋减少阻塞次数

2、reentrantlock
和sync类似,sync的性能提升后,2个方法性能差不多。
主要有一些高级特性:

  • 可等待中断:阻塞时,可设置等待时间,防止死锁
  • 公平锁:阻塞的线程都可以按照顺序获取锁,公平,不像sync都是随机获取
  • 可绑定多个条件

不阻塞同步,乐观锁

这里写图片描述
通过一些硬件设备实现原子性,比如cas。unsafe类中的一些本地方法。

锁优化

  • 自旋锁:进入之前阻塞之前等待很小的一段时间,适用于同步时间很短的一段代码,有自旋次数,自适应功能,根据上次是否自旋成功
  • 锁消除:分析线程中的同步快,如果变量都是线程内的,且对象没有逃逸(逃逸分析),则该锁可以消除
  • 锁粗化:对同一对象循环加锁,可扩展到外面加锁,粗化他
  • 轻量级锁:使用cas操作对象头,在不存在互斥的情况下高效,如果有2个以上线程低效
  • 偏向锁:偏向第一个获取锁的线程?比cas更高效
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值