【Java线程安全】锁
Java都有哪些锁?
synchronized 和 reentranlock是最常见的,其中前者又JVM提供实现,后者有专门对应的java.util.concurrent包提供;同时后者功能更加丰富、灵活
悲观锁和乐观锁
悲观锁认为,每一次走进同步代码都可能发生线程安全问题,因此只要触及代码块都会加锁,而乐观锁则认为大部分情况都不会出现线程安全问题,所以只要出现问题的时候再自旋CAS
可重入锁和不可重入锁
不可重入锁,就是某线程获取该锁但未释放的时候,如果再次获取该锁,则只能等待;而可重入锁不需要等待,只需要为锁数量加1;其中注意,synchronized和reentrantlock都是可重入锁
Synchronized
对象头信息:存储对象年龄,Class实例地址等
监视器信息:EntrySet和WaitSet,前者是Block状态的线程队列,后者是Wait状态的线程队列
JVM实现的锁,实现原理是利用操作系统的内核态的Mutex互斥量实现的,因为涉及内核态的调用所以一般认为是重量级锁,但后面已经被官方优化过,所以很难说synchronized就效率很低,优化的主要思想还是乐观锁,优化方案有:适应性自旋锁、锁消除、锁粗化、轻量级锁、偏向锁
【自旋锁】自旋锁(Spin Lock),在一个线程进入synchronized代码块,获取锁的时候不直接进入ContetionList(之前已经有线程)等候,而是先自旋等待一下,期待Owner线程马上释放锁;这样虽然对ContetionList里面的线程不太公平但是总体效率能提高;因为线程进入ContetionList阻塞,需要进入内核调度状态,非常耗时;
【轻量级锁】如果大部分情况都是一个线程在使用资源,那么轻量级锁就很有用,轻量级锁就是为了在无多线程竞争的环境中使用CAS来代替mutex,一旦发生竞争,两条以上线程争用一个锁就会膨胀,在CAS成功的线程获取锁,而失败的线程则自旋状态,如果自旋成功那么还是偏向锁状态,否则升级为重量级锁。
【偏向锁】(Biased Lock),偏向锁是在第一个获取后,后面的所有重入都不做同步操作,比轻量级锁还轻,因为它取消了同步原语的操作,也就是轻量级锁的CAS操作也不做了,如果发生竞争的时候,会又其他线程来阻塞偏向线程,然后升级为轻量级锁。
【锁粗化】分析代码,然后合并所有锁的获取和进入微一个锁的获取和进入
【锁消除】根据逃逸技术分析代码,如果线程安全,就取消锁。
要知道,sync是基于对象头的监视器的,所以结合对象头的知识,自旋锁,偏向锁工作如下:
每一个线程在准备获取共享资源时:
第一步,检查MarkWord里面是不是放的自己的ThreadId ,如果是,表示当前线程是处于 “偏向锁”
第二步,如果MarkWord不是自己的ThreadId,锁升级,这时候,用CAS来执行切换,新的线程根据MarkWord里面现有的ThreadId,通知之前线程暂停,
之前线程将Markword的内容置为空。
第三步,两个线程都把对象的HashCode复制到自己新建的用于存储锁的记录空间,接着开始通过CAS操作,
把共享对象的MarKword的内容修改为自己新建的记录空间的地址的方式竞争MarkWord,
第四步,第三步中成功执行CAS的获得资源,失败的则进入自旋
第五步,自旋的线程在自旋过程中,成功获得资源(即之前获的资源的线程执行完成并释放了共享资源),则整个状态依然处于 轻量级锁的状态,如果自旋失败
第六步,进入重量级锁的状态,这个时候,自旋的线程进行阻塞,等待之前线程执行完成并唤醒自己
性能差:为什么synchronize性能差呢,因为该锁利用操作系统的互斥实现,所以会切换内核态和用户态,这过程的开销极大;而线程的阻塞消耗一般,所以Reentrantlock一直在用户态消耗不大。
Renentrantlock
J.U.C提供的锁,实现方式是利用volatile和cas自旋的方式实现,主要核心组件是AQS,该知识点请参见我的另一篇参见AQS的文章
【Java线程安全】锁的更多相关文章
- Java线程:锁
一.锁的原理 Java中每个对象都有一个内置锁,当程序运行到非静态的synchronized同步方法上时,自动获得与正在执行的代码类的当前实例(this实例)有关的锁.获得一个对象的锁也称为获取锁.锁 ...
- Java 线程与锁
Synchronization synchronized语法可以获取锁, 当其他线程持有锁的时候该线程想要获取锁将会进入等待状态, 直到没有其他线程持有该锁 显示使用 synchronized (lo ...
- Java线程与锁
概要:线程的实现方法. 线程调度.线程状态及转换.线程安全(5种分类.3种实现方法.锁优化技术) 进程是OS进行资源分配的基本单位,线程是CPU调度的基本单位. 1.线程的实现方法 可参阅 我是一个进 ...
- java 线程 Lock 锁使用Condition实现线程的等待(await)与通知(signal)
一.Condition 类 在前面我们学习与synchronized锁配合的线程等待(Object.wait)与线程通知(Object.notify),那么对于JDK1.5 的 java.util.c ...
- java线程 公平锁 ReentrantLock(boolean fair)
一.公平锁 1.为什么有公平锁 CPU在调度线程的时候是在等待队列里随机挑选一个线程,由于这种随机性所以是无法保证线程先到先得的(synchronized控制的锁就是这种非公平锁).但这样就会产生饥饿 ...
- 【Java线程】锁机制:synchronized、Lock、Condition
http://www.infoq.com/cn/articles/java-memory-model-5 深入理解Java内存模型(五)——锁 http://www.ibm.com/develope ...
- Java线程同步锁
把synchronized当作函数修饰符时,示例代码如下: Public synchronized void method(){ //-. } 这也就是同步方法,那这时synchronized锁定的是 ...
- 【java线程】锁机制
转载于:https://blog.csdn.net/vking_wang/article/details/9952063 http://www.infoq.com/cn/articles/java-m ...
- 【Java线程】锁机制:synchronized、Lock、Condition(转)
原文地址 1.synchronized 把代码块声明为 synchronized,有两个重要后果,通常是指该代码具有 原子性(atomicity)和 可见性(visibility). 1.1 原子性 ...
- Java线程八锁
package com.atguigu.juc1205; import java.util.concurrent.TimeUnit; class Phone//Phone.java ---> P ...
随机推荐
- SharePoint 配置PowerShell任务计划
前言 最近,有这么个需求,需要定时为SharePoint更新内容,所以,就想到了PowerShell命令和任务计划(Windows自带的功能,英文叫Task Schedule,在开始菜单里就能找到), ...
- android:Android中用文件初始化sqlite数据库(zz)
很多时候在应用安装初始化时,需要创建本地数据库,同时为数据库添加数据,之后再从数据库中读取数据. 这里有2个思路 1.先在本地创建一个能支持android使用的sqlite数据库文件,启动时, ...
- MySQL DBA工作角色和职责介绍
MySQL DBA分架构DBA,运维DBA和开发DBA三种角色,职责介绍如下:
- VS2017环境下安装AO10.2的方法
软件版本 Visual Studio的全称.简称及版本号对应关系为: Microsoft Visual Studio 2002 VS2002 VC7.0 Microsoft Visual Studio ...
- html5使用canvas实现毫秒级画心电图
- angular 2 - 004 routing 路由
https://angular.io/tutorial/toh-pt5 定义一个模块用来定义路由 src/app/app-routing.module.ts import { NgModule } f ...
- 每天一个linux命令:top
1.命令简介 top (top) 令经常用来实时监控linux的系统状况,比如cpu.内存的使用,类似于Windows的任务管理器. 2.用法 top -hv | -abcHimMsS -d dela ...
- 【转】关于提示can't load package 'xxx.bpl.' 错误问题的解决方法
转自: http://blog.sina.com.cn/s/blog_44fa172f0102v9x3.html 'xxx.bpl'包实际存在, 路径并且正确. 但是总提示'can ...
- 物联网系统与CoAP之Hello,World
物联网系统与CoAP Hello,World 关于CoAP与物联网系统我们在上一篇中(ps:CoAP与物联网系统)中做一个简单的介绍,接着我们便開始试试CoAP协议的应用 CoAP应用 開始之前我们须 ...
- QT信号/槽
在我的理解中,QT和Android都是类似的开发框架,都是由开发团队封装了各式各样的接口和数据结构.将一些问题的解决方法简单化比如QT中将线程封装为QThread,派生类通过重写run方法来将代码投入 ...