自旋锁

锁优化

被刻印的时光 ゝ 提交于 2019-11-30 17:59:36
锁优化 为了在线程之间更高效地共享数据,解决竞争问题,从而提高程序的执行效率,实现了多种锁优化技术。 自旋锁与自适应自旋 互斥同步对性能最大的影响:阻塞的实现,挂起和恢复线程的操作都需要转入内核态中完成。由于在很多时候,共享数据的锁定状态只会持续很短的时间,为了这段时间去进行挂起和恢复线程并不值得。因此可以考虑:当物理机有多个处理器,可以多次并行执行多个线程,此时可以让后面请求锁的线程稍等一会儿,但不放弃处理器的执行时间,看看持有锁的线程是否很快释放锁。为了让线程等待,会让线程执行一个忙循环(自旋)。 自旋锁 :如果锁被占用的时间比较短,自旋等待的效果很好,避免了线程切换的开销。如果锁占用时间很长,自旋只会白白消耗处理器资源,因此自旋等待的时间会有一个限度。一般自旋次数 默认是 10次。自旋等待不能代替阻塞,主要原因是 虽然避免了线程切换的开销,但是需要占用处理器的执行时间。 自适应自旋 :自适应表示 自旋的时间不固定,而是由 前一次在同一个锁上的 自旋时间 及 锁的拥有者状态 来决定。 锁消除 对于一些代码要求同步,但被检测不可能存在共享数据竞争。此时会将同步锁移除。 锁粗化 原则上:总是要求 同步块的作用范围尽可能的小。这样是使得 需要同步的操作数量尽可能变小,如果存在锁竞争,等待锁的线程也能尽快的拿到锁。 如果虚拟机检测到有一连串的操作 都是对同一个对象加锁

并发下常用关键字的原理

风流意气都作罢 提交于 2019-11-28 17:25:20
对Synchronized的理解 synchronized关键字解决的是多个线程之间访问资源的同步性,synchronized关键字可以保证被它修饰的方法或者代码块在任意时刻只能有一个线程执行。 另外,在 Java 早期版本中,synchronized属于重量级锁,效率低下,因为监视器锁(monitor)是依赖于底层的操作系统的 Mutex Lock 来实现的,Java 的线程是映射到操作系统的原生线程之上的。如果要挂起或者唤醒一个线程,都需要操作系统帮忙完成,而操作系统实现线程之间的切换时需要从用户态转换到内核态,这个状态之间的转换需要相对比较长的时间,时间成本相对较高,这也是为什么早期的 synchronized 效率低的原因。在 Java 6 之后 Java 官方对从 JVM 层面对synchronized 较大优化,所以现在的 synchronized 锁效率也优化得很不错了。JDK1.6对锁的实现引入了大量的优化,如自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减少锁操作的开销。 synchronized关键字最主要的三种使用方式: 修饰实例方法: 作用于当前对象实例加锁,进入同步代码前要获得当前对象实例的锁 修饰静态方法: :也就是给当前类加锁,会作用于类的所有对象实例,因为静态成员不属于任何一个实例对象,是类成员( static

JVM学习(九):锁优化

房东的猫 提交于 2019-11-28 12:34:22
1、高效并发是JDK1.5到JDK1.6的一个重要改进,出现了 适应性自旋 (Adaptive Spinning)、 锁消除 (Lock Elimination)、 锁粗化 (Lock Coarsening)、 轻量级锁 (Lightweight Locking)和 偏向锁 (Biased Locking)等一系列锁优化技术。 2、自旋锁与自适应自旋: (1) 自旋锁 :互斥同步对性能最大的影响是阻塞的实现需要转入内核态完成,由于通常情况下共享数据的锁定状态只会持续很短的一段时间,如果让一个线程在等待获取锁的时候多等一会, 占用CPU的执行时间 但是不会进入阻塞状态, 执行一个忙循环 (自旋),即实现了自旋锁。 (2)自旋锁在JDK1.4.2中已经引入, 自旋不能代替阻塞 ,因为自旋需要占用处理器时间,自旋等待的时间必须有限制,默认自旋次数为10次,可以使用参数 -XX:PreBlockSpin 设置。 (3) 自适应自旋 :JDK1.6引入了自适应的自旋锁,即自旋的时间不再固定,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。如果判断出自旋获取锁的成功概率大,则允许自旋等待较长时间,反之可能省略自旋过程直接进入阻塞,避免浪费处理器资源。 3、 锁消除 :虚拟机即时编译器在运行时,对于有些代码上同步,但被检测到不可能存在共享数据竞争的锁进行消除, 无需同步直接执行

自旋锁

北慕城南 提交于 2019-11-28 05:58:28
原创转载请注明出处: https://www.cnblogs.com/agilestyle/p/11395994.html CAS CAS算法是乐观锁的一种实现方式,CAS算法中又涉及到自旋锁。 CAS是英文单词Compare and Swap(比较并交换),是一种有名的无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。 CAS算法涉及到三个操作数 1.需要读写的内存值 V 2.进行比较的值 A 3.拟写入的新值 B 更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B,否则不会执行任何操作。一般情况下是一个自旋操作,即不断的重试。 自旋锁 自旋锁(spinlock):是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。 它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用

java中的各种锁详细介绍

杀马特。学长 韩版系。学妹 提交于 2019-11-27 13:35:32
转自: https://blog.csdn.net/axiaoboge/article/details/84335452 Java提供了种类丰富的锁,每种锁因其特性的不同,在适当的场景下能够展现出非常高的效率。本文旨在对锁相关源码(本文中的源码来自JDK 8)、使用场景进行举例,为读者介绍主流锁的知识点,以及不同的锁的适用场景。 Java中往往是按照是否含有某一特性来定义锁,我们通过特性将锁进行分组归类,再使用对比的方式进行介绍,帮助大家更快捷的理解相关知识。下面给出本文内容的总体分类目录: 1. 乐观锁 VS 悲观锁 乐观锁与悲观锁是一种广义上的概念,体现了看待线程同步的不同角度。在Java和数据库中都有此概念对应的实际应用。 先说概念。对于同一个数据的并发操作,悲观锁认为自己在使用数据的时候一定有别的线程来修改数据,因此在获取数据的时候会先加锁,确保数据不会被别的线程修改。Java中,synchronized关键字和Lock的实现类都是悲观锁。 而乐观锁认为自己在使用数据时不会有别的线程修改数据,所以不会添加锁,只是在更新数据的时候去判断之前有没有别的线程更新了这个数据。如果这个数据没有被更新,当前线程将自己修改的数据成功写入。如果数据已经被其他线程更新,则根据不同的实现方式执行不同的操作(例如报错或者自动重试)。 乐观锁在Java中是通过使用无锁编程来实现

Linux内核同步方法

百般思念 提交于 2019-11-27 00:43:34
1、原子操作,是其它同步方法的基础。 2、自旋锁,线程试图获取一个已经被别人持有的自旋锁,当前线程处于忙等待,占用cpu资源。 3、读写自旋锁,根据通用性和针对性的特点,普通自旋锁在特定场景下的表现会退化。因此,提供了读写自旋锁,读锁可以加读锁,不能加写锁,写锁不能加任何锁。 4、需要注意的几项:   普通自旋锁是不能递归的。读锁可以递归,写锁也不能递归。   表面上锁的是代码,实际上锁的是共享数据。   使用读写锁的时候,需要注意,读锁可以加读锁,多个线程都占用读锁,必须所有的线程都释放,才能加上写锁,这往往会导致写锁长时间处于饥饿状态。 5、自旋锁存在的问题,线程试图获取一个已经被别人持有的自旋锁,当前线程处于忙等待,占用cpu资源。怎么解决这个问题?   使用信号量,信号量是一种睡眠锁。一个任务试图获取被别人占有的信号量,信号量会将其推进一个等待队列,让其睡眠,当请求的信号量被释放,处于等待队列的任务被唤醒,并获得信号量。 6、需要注意的是,信号量是一种睡眠锁,但它本身也会带有开销,上下文切换,被阻塞的线程要换出换入,也即是说让其睡眠并唤醒它,花费一定的开销。如果每个线程锁的时间很短,一般使用自旋锁,忙等待的时间也很短。如果锁的时间长,使用信号量。 7、相比自旋锁,信号量还有更广泛的用处,使用PV操作不仅能保护共享资源,还能够控制同时访问的数量,还能够控制访问顺序。对于锁

悲观锁、乐观锁、自旋锁、偏向锁、轻量/重量级锁、读写锁 共享锁 互斥锁、公平锁非公平锁、可中断锁及其Java实现

主宰稳场 提交于 2019-11-26 23:55:38
首先要打消一种想法,就是一个锁只能属于一种分类。 其实并不是这样,比如一个锁可以同时是悲观锁、可重入锁、公平锁、可中断锁等等。 就像一个人可以是男人、医生、健身爱好者、游戏玩家,这并不矛盾。 国际惯例,上干货。 〇、synchronized与Lock Java中有两种加锁的方式:一种是用synchronized关键字,另一种是用Lock接口的实现类。 形象地说,synchronized关键字是自动档,可以满足一切日常驾驶需求。 但是如果你想要玩漂移或者各种骚操作,就需要手动档了——各种Lock的实现类。 所以如果你只是想要简单的加个锁,对性能也没什么特别的要求,用synchronized关键字就足够了。 自Java 1.5之后,才在java.util.concurrent.locks包下有了另外一种方式来实现锁,那就是Lock。 也就是说,synchronized是Java语言内置的关键字, 而Lock是一个接口,这个接口的实现类在代码层面实现了锁的功能, 具体细节不在本文展开,有兴趣可以研究下AbstractQueuedSynchronizer类。 ReentrantLock、ReadLock、WriteLock 是Lock接口最重要的三个实现类。 对应了“可重入锁”、“读锁”和“写锁”。 ReadWriteLock其实是一个工厂接口

AQS源码分析--jdk1.8

蓝咒 提交于 2019-11-26 17:18:43
# **JDK1.8** [ArrayList源码分析--jdk1.8](https://blog.51cto.com/hackerxian/2426030) [LinkedList源码分析--jdk1.8](https://blog.51cto.com/hackerxian/2426840) [HashMap源码分析--jdk1.8](https://blog.51cto.com/hackerxian/2427207) [AQS源码分析--jdk1.8](https://blog.51cto.com/hackerxian/2427864) # **AbstractQueuedSynchronizer概述** >   1. AQS是一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架。 >   2. AQS提供了双向链表。 >   3. AQS分为共享模式和独占模式。 >   4.AQS基于volatile内存可见性和CAS原子性操作实现线程间通信操作。 # **AbstractQueuedSynchronizer数据结构** >   数据结构是集合的精华所在,数据结构往往也限制了集合的作用和侧重点,了解各种数据结构是我们分析源码的必经之路。 >   AQS的数据结构如下:双向链表 >   ![](https://s1.51cto.com/images/blog

spin_lock spin_lock_irq spin_lock_irqsave

北城余情 提交于 2019-11-26 12:26:41
1,为啥需要自旋锁 很多时候我们并不能采用其他的锁,比如读写锁、互斥锁、信号量等。一方面这些锁会发生上下文切换,他的时间是不可预期的,对于一些简单的、极短的临界区完全是一种性能损耗;另一方面在中断上下文是不允许睡眠的,除了自旋锁以外的其他任何形式的锁都有可能导致睡眠或者进程切换,这是违背了中断的设计初衷,会发生不可预知的错误。基于两点,我们需要自旋锁,他是不可替代的。 2,为啥自旋锁禁止抢占 这一点其实很好理解,当一个 CPU 获取到一把自旋锁之后,开始执行临界区代码,此时假设他的时间片运转完毕,进程调度会主动触发调度将其调走,执行另一个线程/进程,结果恰巧了这个线程/进程也需要用到该自旋锁,而上一个线程/进程还在停留在临界区内未释放锁,导致本进程无法获取到锁而形成死锁,所以自旋锁为了规避此类情形的出现从而直接禁止对已经开始运行的临界区设置禁止抢占标志。 3,为什么临界区禁止睡眠 如果自旋锁锁住以后进入睡眠,而此时又不能进行处理器抢占,内核的调取器无法调取其他进程获得该 CPU,从而导致该 CPU 被挂起;同时该进程也无法自唤醒且一直持有该自旋锁,进一步会导致其他使用该自旋锁的位置出现死锁。 4,spin_lock 系列的分别 每一种锁出现都有自己的原因,spin_lock 系列的锁就是为了解决这一个又一个的问题才会新增的各种自旋锁变种,这也符合现代计算机代码设计逻辑