深入理解Java虚拟机(6)Java线程

Java线程

Java的线程是通过映射到系统的原生线程来实现的。

线程的实现

与linux操作系统中类似,分为三种方式:内核线程、用户线程、内核和用户线程昏庸(N:M的比例)

线程调度

分为协同式线程调度和抢占式线程调度

  1. 协同式线程调度
    线程自己控制执行时间,线程把自己的工作执行完之后,主动通知系统切换到另外一个线程上。
    优点:实现简单,线程做完自己的事情后才会进行线程切换,切换操作对线程来说是可知的,就没有线程同步的问题。
    缺点:线程执行时间不可控,如果线程一直不通知系统进行线程切换,整个系统就会阻塞。

  2. 抢占式线程调度
    系统为线程分配执行时间,线程的切换不由线程本身来决定,线程的执行时间是系统可控的,不会有一个线程阻塞而导致整个进程阻塞的问题,Java使用的是抢占式线程调度(另外还会根据线程优先级来执行线程)。

状态转换

如图所示:线程状态转换关系
如上图,有五种线程状态:New、Runnable、Waiting、Timed Waiting(限期等待)、Blocked、Terminated。

线程安全

线程安全的五个层次:不可变、绝对线程安全、相对线程安全、线程兼容、线程对立。

实现方式:

  1. 互斥同步(线程阻塞和唤醒)
    互斥是方法,同步是目的。类似于linux操作系统中的信号量、互斥量,线程操作会映射到操作系统的线程上,synchronized同步关键字会从用户态切换到核心态,重量级操作,十分耗时,尽量少用。
  2. 非阻塞同步(借用原子类)
    该实现方式是基于冲突检测的,即先进行操作,如果没有其他线程争用共享资源,则操作成功,如果共享数据有争用,产生了冲突,就采取其他的补偿措施(需要借助原子类,原子指令集)
  3. 无同步方案
    比如纯代码,不依赖存储在堆上的数据和公用的系统资源;比如线程本地存储,即共享数据都放在同一个线程内运行,比如web交互中的一个请求对应一个服务器线程。

锁优化(虚拟机自动优化)

  1. 自旋锁和自适应自旋
    互斥同步是通过阻塞线程来实现的,挂起线程和恢复线程需要从用户态转换到内核态,消耗较大,而共享数据的锁定状态只会持续很短的时间,为此挂起和恢复线程很不值得,如果两个或以上的线程同时并行执行,可以让后面请求锁的线程“稍等一下”,不放弃处理器时间(不挂起),只需要执行一个忙循环,即自旋,等持有锁的线程释放锁后再运行,问题是当持有锁的线程一直不释放锁,那么自旋的锁会一直自旋,会浪费处理器时间而不产生任何价值。
    而自适应自旋即自旋的时间不再固定,而是根据前一次在同一个锁上的自旋时间及锁的拥有者状态来决定。
  2. 锁消除
    即虚拟机对一些代码上要求同步,但是被检测出不可能存在共享数据竞争的锁进行消除。这句话可能听起来很怪,但是很多的同步措施不是程序员所为,而是很多的api都采取了同步措施,在调用的过程中就引入了同步手段。
  3. 锁粗化
    比如StringBuilder对象连续的append,此时锁会粗化到整个操作的序列外部,而不是每执行一次append就加一次锁,然后释放一次锁。此时只会加一次锁。
  4. 轻量级锁
    轻量级锁对应重量级锁,重量级锁即互斥同步锁,使用CAS操作(compare and swap 比较与替换),轻量级锁使用CAS操作代替互斥同步,适用于无竞争的情况,在无竞争的情况下使用CAS操作消除同步使用的互斥量。
  5. 偏向锁
    轻量级锁是在无竞争的情况下使用CAS操作消除同步使用的互斥量,而偏向锁是在无竞争的情况下消除整个同步。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值