自旋

linux同步机制

淺唱寂寞╮ 提交于 2019-11-28 08:34:14
1、自旋锁 获得自旋锁之后禁止内核抢占,但可以被中断上半部打断。运行于中断上下文 单cpu不可抢占内核:空操作 单cpu可抢占内核:禁止内核抢占,不发生自旋 多cpu可抢占内核:禁止内核抢占+自旋 2、互斥锁 内核可以抢占,可以被其他进程抢占,运行于进程上下文 3、读写锁 由于其特殊的逻辑使得其效率相对普通的互斥锁和自旋锁要慢一个数量级,按POSIX标准 在线程申请读锁并未释放前本线程申请写锁是成功的,但运行后的逻辑结果是无法预测。读和写同时获取锁,写具有优先获取。特殊的自旋锁,禁止抢占。 4、顺序锁 对读写锁的一种优化,禁止内核抢占,读和写可以同时进行,多个读者可以同时访问临界资源,但不能同时写 读写可以同时进行这是读写锁不具备的,但使用顺序锁也有限制条件:访问的临界资源不能是指针 5、RCU(read-copy update) 读写可以同时进行,写数据时,先拷贝然后修改,再用更新好的数据覆盖原有数据。 同样获得锁之后禁止内核抢占 6、递归锁 互斥锁的一个特例,互斥锁设置参数PTHREAD_MUTEX_RECURSIVE_NP,运行互斥锁递归加锁和释放锁 7、原子操作 8、信号量 9、信号 10、barrier(信号屏障) barrier()函数前后的代码执行不能越过barrier 来源: https://www.cnblogs.com/zhu-g5may/p/11402395

悲观锁与乐观锁

不问归期 提交于 2019-11-28 07:20:28
悲观锁(多写场景) 总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁,即 共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程 。 传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。 乐观锁(多读场景) 总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。 乐观锁实现的两种方式 版本号机制 一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加1。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作

自旋锁

北慕城南 提交于 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):是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。 它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用

偏向锁 / 轻量级锁 / 重量级锁

被刻印的时光 ゝ 提交于 2019-11-28 05:56:51
原创转载请注明出处: https://www.cnblogs.com/agilestyle/p/11395931.html 锁的状态 无锁状态 偏向锁状态 轻量级锁状态 重量级锁状态 锁的状态是通过对象监视器在对象头中的字段来表明的。 为了提升性能,JDK1.6引入了偏向锁、轻量级锁、重量级锁概念,来减少锁竞争带来的上下文切换,而正是新增的Java对象头实现了锁升级功能。 当Java对象呗Synchronized关键字修饰成同步锁后,围绕这个锁的一系列升级操作都将和Java对象头有关。 Java对象头 在JDK1.6的JVM中,对象实例在堆内存中被分为了三个部分:对象头、实例数据、对齐填充。其中对象头由Mark Word、指向类的指针以及数组长度三部分组成。 Mark Word记录了对象和锁有关的信息。Mark Word在64位JVM中的长度是64bit,在64位JVM的存储结构如下图所示 锁升级主要依赖于Mark Word中的锁标志位和释放偏向锁标志位,Synchronized同步锁就是从偏向锁开始的,四种状态会随着竞争的情况逐渐升级到轻量级锁,最终升级到重量级锁,而且是不可逆的过程,即不可降级。 这四种状态都不是Java语言中的锁,而是JVM在使用synchronized时为了提高锁的获取与释放效率而做的优。 偏向锁 偏向锁是指一段同步代码一直被一个线程所访问

别说谁变了你拦得住时间么 提交于 2019-11-28 05:23:52
【同步】:   是指散步在不同任务之间的若干程序片断,它们的运行必须严格按照规定的某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。最基本的场景就是:两个或两个以上的进程或线程在运行过程中协同步调,按预定的先后次序运行。比如 A 任务的运行依赖于 B 任务产生的数据。 【互斥】:   是指散步在不同任务之间的若干程序片断,当某个任务运行其中一个程序片段时,其它任务就不能运行它们之中的任一程序片段,只能等到该任务运行完这个程序片段后才可以运行。最基本的场景就是:一个公共资源同一时刻只能被一个进程或线程使用,多个进程或线程不能同时使用公共资源。 【互斥锁的特点】: 1. 原子性:把一个互斥量锁定为一个原子操作,这意味着操作系统(或pthread函数库)保证了如果一个线程锁定了一个互斥量,没有其他线程在同一时间可以成功锁定这个互斥量; 2. 唯一性:如果一个线程锁定了一个互斥量,在它解除锁定之前,没有其他线程可以锁定这个互斥量; 3. 非繁忙等待:如果一个线程已经锁定了一个互斥量,第二个线程又试图去锁定这个互斥量,则第二个线程将被挂起(不占用任何cpu资源),直到第一个线程解除对这个互斥量的锁定为止,第二个线程则被唤醒并继续执行,同时锁定这个互斥量。 【互斥锁的操作流程如下】: 1. 在访问共享资源后临界区域前,对互斥锁进行加锁; 2. 在访问完成后释放互斥锁导上的锁

乐观锁与悲观锁【讲的很好】

。_饼干妹妹 提交于 2019-11-28 03:24:06
转: 面试必备之乐观锁与悲观锁 2018年07月16日 22:34:26 SnailClimb在csdn 阅读数 76723 更多 所属专栏: Java面试通关手册 版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接: https://blog.csdn.net/qq_34337272/article/details/81072874 推荐阅读: 如何在技术领域持续成长 后端程序员必备的Linux基础知识 后端必备——数据通信知识(RPC、消息队列)一站式总结 何谓悲观锁与乐观锁 乐观锁对应于生活中乐观的人总是想着事情往好的方向发展,悲观锁对应于生活中悲观的人总是想着事情往坏的方向发展。这两种人各有优缺点,不能不以场景而定说一种人好于另外一种人。 悲观锁 总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁( 共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程 )。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中 synchronized 和 ReentrantLock 等独占锁就是悲观锁思想的实现。 乐观锁 总是假设最好的情况

AQS

烈酒焚心 提交于 2019-11-27 18:27:39
AQS AQS 是一个抽样同步器,可以通过这个快速实现一些需要同步对象,可以编写各种锁 使用while编写一个简单的自旋锁很容易,但是有的时候,使用while不断的自旋获取锁资源,在别的线程获取到资源的情况下而且使用较长的时间,当前线程还在不断的自旋,cpu有较大的浪费,但是操作线程的状态比较复杂,使用Sleep或者Park以及什么时候唤醒线程都不方便写,因此如果使用AQS,就不再需要写这些线程唤醒阻塞的代码 使用的算法: CHL 相关链接 https://www.cnblogs.com/yuyutianxia/p/4296220.html https://www.jianshu.com/p/5ad8539e25c3 简单理解: 每一个 AQS 都有一个队列结构,如果没有获取到资源加入到队列末尾,队列里面所有的线程(实际上是一个包装线程的一个节点对象)都是阻塞状态,只有当调用release方法的时候才会唤醒,每次唤醒头节点,当然,因为release有可能被并发调用所以其他的节点也有可能被唤醒,对于每一个唤醒的线程,自旋(一次)判断自己是不是头节点,如果是头节点那么会尝试获取锁,获取成功会移除队列 https://www.cnblogs.com/iou123lg/p/9464385.html https://www.cnblogs.com/barrywxx/p/8678698

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中是通过使用无锁编程来实现

Java中的锁

人盡茶涼 提交于 2019-11-27 08:14:47
1.可重入锁 synchronized和Lock都是可重入锁 表明了锁的分配机制是基于线程,而不是基于方法 例如,在一个同步方法中调用了另一个同步方法,再进入第二个同步方法时,不需要重新申请锁 2.可中断锁 synchronized是不可中断的。   一个线程已经获得了某对象的锁,另一个线程想获得该对象的锁时,必须等待,直到第一个线程释放锁(执行完、异常) Lock调用lockInterruptibly方法获得锁时,是可中断的。   一个线程已经获得了某对象的锁,另一个线程想获得该对象的锁时,等待,在等待过程中,可以调用该线程的interrupt方法终端等待 3.公平锁、非公平锁 公平锁:按照请求的顺序获得锁 非公平锁:不保证获取锁的顺序,吞吐量高,造成优先级反转或者饥饿现象(有的线程一直等待) synchronized是非公平锁 Lock的实现类:ReentrantLock它默认情况下是非公平锁,在创建相应对象时,使用重载的构造器,传入参数(true),设置成公平锁 4.共享锁、排它锁 共享锁:锁可以被多个线程持有 排它锁:锁只能被一个线程持有 synchronized和Lock都是排它锁 ReadWriteLock(读写锁),其读锁是共享锁,写锁是排它锁      实现类ReentrantReadWriteLock       5.乐观锁、悲观锁 乐观锁:对同一数据的并发操作

Synchronized升级过程总结

孤人 提交于 2019-11-27 08:09:35
要理解Synchronized,首先要清楚偏向锁,轻量级锁和重量级锁,在使用方面需要有wait/wait(time)/notify/notifyAll等,下 面我们就来介绍一下Synchronized的流程和使用方法; Synchronized的升级过程 (Java SE 1.6中为了减少获得锁和释放锁带来的 性能消耗而引入的偏向锁和轻量级锁) Synchronized的升级顺序是 无锁–>偏向锁–>轻量级锁–>重量级锁,顺内不可逆。 偏向锁 当一个线程访问 同步代码块 并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,偏向锁是一个可重入的锁,以后该线程在进入和退出该同步代码块时不需要花费 CAS 操作来加锁和解锁,而只需简单的 测试一下对象头的 Mark Word 里是否存储着指向当前线程的偏向锁(当前线程的线程ID) ,如果测试成功,表示线程已经获得了锁,如果测试失败,则需要再测试下 Mark Word 中偏向锁的标识是否设置成 1(表示当前是偏向锁),如果偏向锁标识是1, 则使用 CAS 进行锁获取 ,偏向锁标识不是1,则尝试使用 CAS 将对象头的偏向锁指向当前线程 ,上述两种CAS获取锁的操作,如果 CAS操作成功则获取到了偏向锁 , 失败则代表出现了锁竞争,需要锁撤销操作 。 锁撤销 偏向锁使用了一种等到 竞争出现才释放锁 的机制