Java多线程学习笔记
Posted 等待戈多儿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java多线程学习笔记相关的知识,希望对你有一定的参考价值。
参考《深入理解Java虚拟机-JVM高级特性与最佳实践》第五部分 高效并发
Java线程的实现在windows和linux中是使用一对一的线程模型实现的,即一条Java线程就映射到一条轻量级线程之中,因为Windows和linux系统提供的线程模型就是一对一的,在Solaris平台中,操作系统线程模型可以一对一也可以一对多,因此Solaris版的JDK可通过参数指定JVM使用哪种线程模型。
线程调度:
(1)协同式线程调度:线程把自己的工作执行完之后,主动通知系统切换到另外一个线程上。不存在线程安全问题。但是线程执行时间不可控制,会导致阻塞。
(2)抢占式线程调度(Java):每个线程将由系统来分配执行时间,线程切换由自己决定,线程可以通过Thread.yield()让出执行时间,但是不可以自己获取执行时间。虽然可以 建议系统给予线程多一点执行时间(设定优先级),但是这是由操作系统决定的,不一定靠谱。
线程状态:
在任意一个时间点,一个线程有且只能有一种状态:
1.新建(new):创建后尚未启动
2.运行(runnable):包括操作系统线程状态中的running和ready,此线程可能正在执行,也可能正在等待CPU分配执行时间。
3.无限期等待(waiting):不会被CPU分配执行时间,需要等其他线程显示唤醒它。
没有设置Timeout参数的Object.wait()方法
没有设置Timeout参数的Thread.join()方法
LockSupport.park()方法
4.限期等待(thread waiting):无须等待其他线程显示唤醒,一定只是之后由系统自动唤醒
Thread.sleep()
设置Timeout参数的Object.wait()方法
设置Timeout参数的Thread.join()方法
LockSupport.parkNanos()方法
LockSupport.parkUntil()方法
6.结束(terminated):已经终止线程的状态,线程已经结束执行。
线程安全:
当多个线程同时访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方式进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那么这个对象是线程安全的。
这个定义要求代码本身封装了所有必要的正确性的保障手段(如互斥同步),令调用无须关心多线程问题。
共享数据分类:
1.不可变:不可变带来的安全性是最简单和最纯粹的。Integer构造函数将内部状态变量value定义为final来保障不可变。
2.绝对线程安全:API中标注自己是线程安全的类也不是绝对线程安全的。
3.相对线程安全:通常意义上讲的线程安全。对于特定顺序的连续调用需要采用额外的手段保证同步调用的正确性。
4.线程兼容:本身不是线程安全,但是可以通过在调用端正确的使用同步手段来保证对象在并发环境中可以安全使用。通常所说线程不安全的类。
5.线程对立:无论是否使用同步措施,都无法正确使用。
线程安全的实现方法:
1.互斥同步(阻塞同步):保证共享数据在同一个时刻只被一个线程使用。进行阻塞和唤醒具有性能问题。属于悲观并发策略。
2.非阻塞同步:基于检测冲突的乐观并发策略。线程先进行操作,如果没有线程争用就成功了,如果共享数据有争用,产生了冲突,那再采取补偿措施(如不断重试,直到成功为止),这个策略不需要把线程挂起。但是需要依赖“硬件指令集的发展”,来保障操作和冲突检测具备原子性,如果还使用互斥同步就失去了意义。
3.无同步方案:如果一个方法本来就不涉及共享数据,则无需同步措施。
天生安全的代码:
可重入代码:可以在代码执行的任何时刻被中段,返回控制权之后还能真确执行。
线程本地存储:把共享数据控制在一个线程范围之内。
锁优化(虚拟机层面的):
1.自旋锁(旋的时间短才好)与自适应锁
不放弃处理器执行时间,看看持有锁的线程是否很快释放锁,让线程执行一个忙循环(自旋)。不能代替阻塞。
自适应锁是自旋的时间不再固定了,而是由前一次在同一个锁上的自旋时间及锁的持有者的状态来决定。允许自旋等待的时间持续更长。
2.锁消除:虚拟机及时编译器在运行时,对同步代码中不可能存在数据竞争的所进行消除。
3.锁粗化:把锁同步的范围扩大,防止即使没有线程竞争的情况下进行频繁的互斥同步。
4.轻量级锁:不能代替传统的锁机制(重量级锁),本意是在没有多线程竞争的前提下,减少传统重量级锁的使用,减少性能消耗。使用CAS操作去清除同步使用的互斥量。
5.偏向锁:消除数据在无竞争的情况下的同步原语,把整个同步都清除掉,包括CAS操作。偏向于获得他的第一个线程,如果在接下来的执行过程中,该锁没有被其他线程获取,则持有偏向锁的线程永远不需要进行同步。
以上是关于Java多线程学习笔记的主要内容,如果未能解决你的问题,请参考以下文章