并发编程--线程同步之 synchronized关键字(一)
线程同步主要就是两种实现:
- ReentrantLock 显示锁
- Synchronized 隐式锁
一、对synchronized的一个整体认知
1、JDK1.6之前
整体了解那肯定就得从synchronized升级前后开始了解,正所谓士别三日当刮目相待,JDK1.6之前,synchronized确实很笨重,因为他是强依赖于操作系统的,不管你多少个线程,他都默认你竞争激烈,直接上重头戏,哈哈。
2、JDK1.6后,包含1.6
但是JDK1.6则对synchronized做了重大优化,引入了锁粗化,锁消除,偏向锁,轻量级锁,自旋锁等技术来减小锁操作的开销。
就比如当有一个线程时,就是偏向锁。
当两三个线程,但是由于执行速度快,所以竞争不激烈的情况,则是轻量级锁,就比如有线程A,B,C,A拿到线程,B,C两个线程并非严格等待阻塞着,而是循环请求,等待A释放,就是因为本身的竞争不激烈,这也就是所谓的自旋锁。
假如循环了100次还未拿到锁,这种就有可能升级成重量级锁去竞争。
二、锁的膨胀升级过程:
锁的状态总共有四种,无锁状态、偏向锁、轻量级锁和重量级锁。随着锁的竞争,锁可以从偏向锁升级到轻量级锁,再升级的重量级锁,但是锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级。从JDK 1.6 中默认是开启偏向锁和轻量级锁的,可以通过-XX:-UseBiasedLocking来禁用偏向锁。
1、偏向锁
偏向锁是Java 6之后加入的新锁,它是一种针对加锁操作的优化手段。
经过研究发现,在大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,因此为了减少同一线程获取锁(会涉及到一些CAS操作,耗时)的代价而引入偏向锁。
比如线程A有可能多次获得锁,当线程A获取了锁,那么引入偏向锁的概念之后,当再次请求锁时,无需再做任何同步操作,即获取锁的过程,这样就省去了大量有关锁申请的操作,从而也就提供程序的性能
默认开启偏向锁
开启偏向锁:-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0
关闭偏向锁:-XX:-UseBiasedLocking
2、轻量级锁
倘若偏向锁失败,虚拟机并不会立即升级为重量级锁,它还会尝试使用一种称为轻量级锁的优化手段(1.6之后加入的),此时Mark Word 的结构也变为轻量级锁的结构。
轻量级锁能够提升程序性能的依据是“对绝大部分的锁,在整个同步周期内都不存在竞争”。
适应场景:
轻量级锁所适应的场景是线程交替执行同步块的场合,如果存在同一时间访问同一锁的场合,就会导致轻量级锁膨胀为重量级锁。
3、自旋锁
轻量级锁失败后,虚拟机为了避免线程真实地在操作系统层面挂起,还会进行一项称为自旋锁的优化手段。这是基于在大多数情况下,线程持有锁的时间都不会太长,如果直接挂起操作系统层面的线程可能会得不偿失,毕竟操作系统实现线程之间的切换时需要从用户态转换到核心态,这个状态之间的转换需要相对比较长的时间,时间成本相对较高,因此自旋锁会假设在不久将来,当前的线程可以获得锁,因此虚拟机会让当前想要获取锁的线程做几个空循环(这也是称为自旋的原因),一般不会太久,可能是50个循环或100循环,在经过若干次循环后,如果得到锁,就顺利进入临界区。如果还不能获得锁,那就会将线程在操作系统层面挂起,这就是自旋锁的优化方式,这种方式确实也是可以提升效率的。最后没办法也就只能升级为重量级锁了。
三、可修饰的对象
synchronized内置锁是一种对象锁(锁的是对象而非引用),作用粒度是对象,可以用来实现对临界资源的同步互斥访问,是可重入的。
- 修饰一个代码块,
被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象 - 修饰一个方法
被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象 - 修改一个静态的方法
其作用的范围是整个静态方法,作用的对象是这个类的所有对象 - 修改一个类
其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象
其实理解也就两类,一种是this,取的锁是对象(代码块,非静态方法);一种是class,取的锁是类(静态方法,类)。
下篇则针对原理,实践理解。
并发编程--线程同步之 synchronized关键字(一)相关推荐
- python 线程同步_Python并发编程-线程同步(线程安全)
Python并发编程-线程同步(线程安全) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 线程同步,线程间协调,通过某种技术,让一个线程访问某些数据时,其它线程不能访问这些数据,直 ...
- JAVA并发编程3_线程同步之synchronized关键字
在上一篇博客里讲解了JAVA的线程的内存模型,见:JAVA并发编程2_线程安全&内存模型,接着上一篇提到的问题解决多线程共享资源的情况下的线程安全问题. 不安全线程分析 public clas ...
- Java线程同步机制synchronized关键字的理解
由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题.Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问. 需要明确的几个问题: ...
- 多线程,线程同步,synchronized关键字的用法
一.什么是多线程 Java多线程实现方式主要有四种:继承Thread类.实现Runnable接口.实现Callable接口通过FutureTask包装器来创建Thread线程.使用ExecutorSe ...
- Java并发编程—线程同步类
原文作者:洲洋1984 原文地址:Java 并发包中的高级同步工具 Java 中的并发包指的是 java.util.concurrent(简称 JUC)包和其子包下的类和接口,它为 Java 的并发提 ...
- 并发编程之深入理解synchronized
并发编程之深入理解synchronized 一.java共享内存带来的线程安全问题 1.1 问题分析 1.2 临界区 1.3 竞态条件 二.synchronized使用 2.1 解决之前的共享问题 三 ...
- 并发编程——线程协作
并发编程--线程协作 前面学习了线程,那么并发编程中,如何协调多个线程来开发呢? Semaphore 信号量跟前面将的同步互斥解决方案--信号量是一个东西,这是JDK的信号量实现. 源码分析 ...
- Java 并发编程 -- 线程池源码实战
一.概述 小编在网上看了好多的关于线程池原理.源码分析相关的文章,但是说实话,没有一篇让我觉得读完之后豁然开朗,完完全全的明白线程池,要么写的太简单,只写了一点皮毛,要么就是是晦涩难懂,看完之后几乎都 ...
- 高并发编程-线程通信_使用wait和notify进行线程间的通信2_多生产者多消费者导致程序假死原因分析
文章目录 概述 jstack或者可视化工具检测是否死锁(没有) 原因分析 概述 高并发编程-线程通信_使用wait和notify进行线程间的通信 - 遗留问题 我们看到了 应用卡住了 .... 怀疑是 ...
最新文章
- cocos2d-x3.0rc打包apk遇到的一些问题记录
- 【UIKit】UILabel使用
- php处理二进制,PHP应用:PHP处理二进制数据的实现方法
- Linux0.00 代码解析(二)
- 【网络编程】一张图了解TCP/IP协议
- Centos 安装 JDK8
- 以太坊源码学习(一)
- 一些避免竞争条件的实例
- TCP和HTTP的区别和联系
- ros 开源物体检测_ROS kinetic + Realsens D435i + ORK + LINEMOD 物体识别
- python表情识别程序_python 实现表情识别
- 教程 | 做一个自己专属的本地 BLAST 数据库
- win10 添加照片查看器
- linux 查看硬盘序列号、设备序列号、系统安装时间
- gmail 设置 smtp_如何在Linux上使用Gmail或SMTP设置电子邮件警报
- 3D游戏建模学习路线
- [记录][问题]Win32调用C++/WinRT DLL
- 如何用机器学习算法计算特征重要性
- 计算机应用基础——计算机软件(三)
- PAData:FCoin潜在受害者或超2000人,人均损失或超25 BTC