自旋

深入分析Synchronized原理

一曲冷凌霜 提交于 2019-12-03 20:06:27
前言 记得开始学习Java的时候,一遇到多线程情况就使用synchronized,相对于当时的我们来说synchronized是这么的神奇而又强大,那个时候我们赋予它一个名字“同步”,也成为了我们解决多线程情况的百试不爽的良药。但是, 随着学习的进行我们知道在JDK1.5之前synchronized是一个重量级锁,相对于j.u.c.Lock,它会显得那么笨重,以至于我们认为它不是那么的高效而慢慢摒弃它 。 不过, 随着Javs SE 1.6对synchronized进行的各种优化后,synchronized并不会显得那么重了 。下面来一起探索synchronized的基本使用、实现机制、Java是如何对它进行了优化、锁优化机制、锁的存储结构等升级过程。 大家可以点击加群【JAVA架构知识学习讨论群】 473984645, (如多你想跳槽换工作,但是技术又不够,或者工作遇到了瓶颈,我这里有一个Java的免费直播课程,讲的是高端的知识点,只要有1-5年的开发工作经验可以加群找我要课堂链接。)注意:是免费的 没有开发经验的误入。 1 基本使用 Synchronized是Java中解决并发问题的一种最常用的方法,也是最简单的一种方法。 Synchronized的作用主要有三个 : 原子性 :确保线程互斥的访问同步代码; 可见性 :保证共享变量的修改能够及时可见

面试必问的Synchronized知道这些就可以了

[亡魂溺海] 提交于 2019-12-03 16:42:52
Synchronized关键字算是Java的元老级锁了,一开始它撑起了Java的同步任务,其用法简单粗暴容易上手。但是有些与它相关的知识点还是需要我们开发者去深入掌握的。比如,我们都知道通过Synchronized锁来实现互斥功能,可以用在方法或者代码块上,那么不同用法都是怎么实现的,以及都经历了了哪些优化等等问题都需要我们扎实的理解。 1.基本用法 2.实现原理 2.1 同步代码块的实现 2.2 同步方法的实现 3.锁升级 3.1 Java对象头介绍 3.2 什么是锁升级 1.基本用法 通常我们可以把Synchronized用在一个方法或者代码块里,方法又有普通方法或者静态方法。 对于普通同步方法,锁是当前实例对象,也就是this public class TestSyn{ private int i=0; public synchronized void incr(){ i++; } } 对于静态同步方法,锁是Class对象 public class TestSyn{ private static int i=0; public static synchronized void incr(){ i++; } } 对于同步代码块,锁是同步代码块里的对象 public class TestSyn{ private int i=0; Object o = new Object();

synchronize底层原理

╄→尐↘猪︶ㄣ 提交于 2019-12-03 11:34:06
1、普通同步方法,锁是当前实例对象 2、静态同步方法,锁是当前类的class对象 3、同步方法块,锁是括号里面的对象 synchronize底层原理: Java 虚拟机中的同步(Synchronization)基于进入和退出Monitor对象实现, 无论是显式同步(有明确的 monitorenter 和 monitorexit 指令,即同步代码块)还是隐式同步都是如此。 同步代码块:monitorenter指令插入到同步代码块的开始位置,monitorexit指令插入到同步代码块的结束位置,JVM需要保证每一个monitorenter都有一个monitorexit与之相对应。任何对象都有一个monitor与之相关联,当且一个monitor被持有之后,他将处于锁定状态。线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor所有权,即尝试获取对象的锁; 对象头: Hotspot虚拟机的对象头主要包括两部分数据:Mark Word(标记字段)、Klass Pointer(类型指针)。其中Klass Point是是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例,Mark Word用于存储对象自身的运行时数据,它是实现轻量级锁和偏向锁的关键。 Mark Word:用于存储对象自身的运行时数据,如哈希码(HashCode)、 GC分代年龄

java锁机制

房东的猫 提交于 2019-12-03 11:07:51
首先需要知道几个名词: 公平锁/非公平锁 可重入锁 独享锁/共享锁 互斥锁/读写锁 乐观锁/悲观锁 分段锁 偏向锁/轻量级锁/重量级锁 自旋锁 公平锁/非公平锁: 公平锁是指多个线程按照申请锁的顺序来获取锁。 非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。有可能,会造成优先级反转或者饥饿现象。 可重入锁: 可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁。 独享锁/共享锁: 独享锁是指该锁一次只能被一个线程所持有。 共享锁是指该锁可被多个线程所持有。 互斥锁/读写锁 上面讲的独享锁/共享锁就是一种广义的说法,互斥锁/读写锁就是具体的实现。 乐观锁/悲观锁 乐观锁与悲观锁不是指具体的什么类型的锁,而是指看待并发同步的角度。 悲观锁认为对于同一个数据的并发操作,一定是会发生修改的,哪怕没有修改,也会认为修改。因此对于同一个数据的并发操作,悲观锁采取加锁的形式。悲观的认为,不加锁的并发操作一定会出问题。 乐观锁则认为对于同一个数据的并发操作,是不会发生修改的。在更新数据的时候,会采用尝试更新,不断重新的方式更新数据。乐观的认为,不加锁的并发操作是没有事情的。 从上面的描述我们可以看出,悲观锁适合写操作非常多的场景,乐观锁适合读操作非常多的场景,不加锁会带来大量的性能提升。 悲观锁在Java中的使用

Synchronized知道这些就可以了

纵然是瞬间 提交于 2019-12-03 02:09:54
Synchronized关键字算是Java的元老级锁了,一开始它撑起了Java的同步任务,其用法简单粗暴容易上手。但是有些与它相关的知识点还是需要我们开发者去深入掌握的。比如,我们都知道通过Synchronized锁来实现互斥功能,可以用在方法或者代码块上,那么不同用法都是怎么实现的,以及都经历了了哪些优化等等问题都需要我们扎实的理解。 1.基本用法 2.实现原理 2.1 同步代码块的实现 2.2 同步方法的实现 3.锁升级 3.1 Java对象头介绍 3.2 什么是锁升级 1.基本用法 通常我们可以把Synchronized用在一个方法或者代码块里,方法又有普通方法或者静态方法。 对于普通同步方法,锁是当前实例对象,也就是this public class TestSyn{ private int i=0; public synchronized void incr(){ i++; } } 对于静态同步方法,锁是Class对象 public class TestSyn{ private static int i=0; public static synchronized void incr(){ i++; } } 对于同步代码块,锁是同步代码块里的对象 public class TestSyn{ private int i=0; Object o = new Object();

synchronized和lock

匿名 (未验证) 提交于 2019-12-03 00:11:01
类别 synchronized Lock 存在层次 Java的关键字 一个类 锁的释放 1.以获取锁的线程执行代码同步代码,释放锁。 2,线程执行发生异常,jvm会让线程释放锁 在finally中必须释放锁,不然容易造成线程死锁 锁的获取 假设A线程获得锁,B线程等待,如果A线程阻塞,则B会一直等 分情况而定,Lock有多个获取锁的方式,线程不用一直等 锁状态 无法判断 可判断 锁类型 可重入,不可中断,非公平 可重入,可判断,可公平 性能 少量同步 大量同步 1.Lock Lock的几个方法 lock() 获取锁 unlock() 释放锁 trylock() 获得锁的状态,返回true和false tryLock(long time,TimeUnit unit) 比tryLock加了时间期限 lockInterruptibly() 2. synchronized 乐观锁 ( Optimistic Locking ) 相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。而乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本( Version )记录机制实现。何谓数据版本?即为数据增加一个版本标识

synchronized 锁优化

匿名 (未验证) 提交于 2019-12-02 23:32:01
jdk1.7之后,synchronized引入了 偏向锁,自旋锁,轻量级锁,重量级锁 自旋锁 当线程在获取锁的时候,如果发现锁已经由其他线程获得,这时候线程会先进行自旋,就是循环。如果在循环次数内这个线程得到了锁,那么他就进入。如果没有就转到轻量级锁 轻量级锁 代码进入同步块的时候,如果对象没有被锁定 虚拟机会在当前栈帧下创建一个lock record的锁记录空间,用来存储锁对象 markword的拷贝。然后虚拟机将使用cas操作将markword更新为指向lock record的指针,如果更新成功 那这个线程就拥有了锁。并更新锁对象的markword 为00 ,表示锁对象处于轻量级锁。 如果更新失败,就说明有其他线程竞争这个锁,如果有2条线程以上,轻量级锁就会升级为重量级锁。 在没有锁竞争的情况下 使用cas 操作,就避免互斥的开销 偏向锁 轻量级锁是在没有锁竞争的情况下,使用cas 操作 去除互斥的操作。那么偏向锁就是在没有锁竞争的情况下,连cas都不用了。 锁会偏向第一个获取它的那个线程。hotpost作者认为,在大多数情况下是没有锁竞争的,并且同一个线程 会重复获得这一把锁。添加偏向锁 就是为了让获得锁的代价更低 当一个线程获取到锁的时候,会使用cas操作,把当前线程的id记录到锁对象的markword中。 以后这个线程在进入和退出这个同步块的时候

第七章 Linux设备驱动开发中的并发控制

匿名 (未验证) 提交于 2019-12-02 21:59:42
阅读笔记-个人记录 7.1并发和竞态 并发 :多个执行单元同时、并行被执行,而并发的执行单元对共享组员的访问很容易导致竞态 竞态发生情况: 1.对称多处理器(SMP)的多个CPU 2.单CPU内进程与抢占它的进程 一个进程在内核执行的时候可能耗完了自己的时间片,也可能被另一个高优先级进程打断,而进程与抢占它的进程访问共享资源的情况 3.中断与进程之间 中断可以打断正在执行的进程,且此时中断服务程序访问进程正在访问的资源,竞态也会发生;中断也有可能被更高优先级中断打断。 解决:保证对共享资源的互斥访问。即一个执行单元在访问共享资源时,其他执行单元被禁止访问 访问共享资源额代码区域成为临界区,需要某种互斥机制加以保护 7.2编译乱序和执行乱序 编译乱序:编译顺序不按照源代码中的顺序 解决:barrier()编译屏障“_asm__volatile_("":::"memory")” 执行乱序: 7.3 中断屏蔽 在进入临界区前屏蔽系统的中断,底层就是让CPU本身不响应中断。 7.4原子操作 7.5自旋锁 需先执行一个原子操作,该操作测试并设置某个内存变量,简单理解:把自旋锁当做一个变量看待,该变量把一个临界区标记为“我当前在运行,请稍等一会”或者是“我当前不在运行,可被使用” Linux自旋锁常用操作4种: (1)定义自旋锁 spinlock_t lock; (2)初始化 spin

Java锁的升级策略 偏向锁 轻量级锁 重量级锁

匿名 (未验证) 提交于 2019-12-02 21:40:30
这三种锁是指锁的状态,并且是专门针对Synchronized关键字。JDK 1.6 为了减少"重量级锁"的性能消耗,引入了“偏向锁”和“轻量级锁”,锁一共拥有4种状态:无锁状态、偏向锁、轻量级锁、重量级锁。锁状态是通过对象头的Mark Word来进行标记的: 锁可以升级但不能降级,意味着偏向锁升级成轻量级锁后不能降级成偏向锁,这种锁升级却不能降级的策略,是为了提高获得锁和释放锁的效率 重量级锁:依赖于底层操作系统的Mutex Lock,线程会被阻塞住 缺点:加锁和解锁需要从用户态切换到内核态,性能消耗较大 轻量级锁:基于重量级锁进行了优化(避免上下文切换,提高了性能),它假设多线程竞争是互相错开的,不会发生线程阻塞,呢么上下文切换就是多余的 第一个特点:采用了CAS操作加锁和解锁,由于轻量级锁的锁记录(Lock Record)是存放在对象头和线程空间里的,因此加锁和解锁不需要上下文切换,性能消耗较小 第二个特点:一旦发生多线程竞争,首先基于“自旋锁”思想,自旋CPU循环等待一段时间,不会发生上下文切换,如果还是无法获得锁,就将锁升级为重量级锁 偏向锁:基于轻量级锁进行了优化(减少多次的加锁和解锁,提高了性能),它假设整个过程只有一个线程获得锁,呢么多次的加锁和解锁就是多余的 特点:在第一次获得锁之后不会释放锁,它会一直持有锁,后续进入锁时只需检查一下锁状态和偏向线程ID是否为自己