- 首先说下其使用特点:
- 排他:一个对象的锁只在一个时间段内,只能被一个线程持有,其它企图持有锁的线程都处于blocked状态(或是自旋状态running)
-
非公平:不是先申请就能先得到锁(jdk1.5后,ReentrantLock可以代替synchronized,可选择公平还是非公平,不过公平锁的吞吐量要低很多,数倍,ReentrantLock的效率不一定更高,但是代码会更易读)
- 内部:
先介绍下对象头信息,JVM里面每个对象都有一个对象头,普通对象两个字,数组3个字(字长为虚拟机位数,32、64)
长度 | 内容 | 说明 |
字(32/64) | Mark Word | 存储对象的hashcode,分代年龄,锁信息 |
字(32/64) | Class Metadata Address | 对象的类对象的指针 |
字(32/64) | Array Length | 数组长度(如果是数组的话) |
在本主题只介绍Mark Word内容,32位jvm如下:
64位如下:
-
偏向锁(Biased):
场景,某线程获得锁之后,为了消除此线程锁重入的开销(CAS),就像此线程得到了偏袒。
对象A,线程T,T竞争A上的锁,动作如下:
先检查,发现对象A处于初始状态(Tag为01,偏向信息为0),可以加偏向锁;
如果A上已经有偏向信息(注意,不是锁,这意味着现在就有或是曾经加过偏向锁,Tag为01,偏向信息为1,Thread Id为T),T也就是当前线程嘛,那就是重入,啥也不用做,继续操作;如果不是当前线程,那就是有不同线程竞争锁,那就要将偏向锁撤销(revode)为轻量锁,再升级为自旋-->重量锁。这个撤销操作,稍后介绍。
这就是加偏向锁的条件及过程,若是其它情况偏向锁都不会启用。
重入:发现有偏向锁,检查threadid是否就是当前线程,是,那么重入成功。解锁:要等到非本线程竞争者出现,才会撤销。(意思是,就算同步块已经完成,mark value也不会恢复未加锁状态)
总结:在没有不同线程加锁的情况下,重入开销小(cas操作都不需要),解锁是被动的(开销也小),但是一旦换个线程来竞争锁,就得-->轻量锁-->自旋-->重量。
-
轻量锁(Light-weight):
场景:线程T1曾经获取了对象A上的锁(最初就是偏向锁,当然也可能是轻量锁),然后释放了,线程T2尝试获取A上的锁,此时轻量锁就派上用场了。
先判断A的Mark Value的内容,无锁,或是曾经有偏向锁;
T2的栈里面会新生成一个lock record对象,其内容就是A的Mark Value的copy;
通过CAS操作,将A的MarkValue设为lock record地址,将tag设为00,如果成功,那么就获取锁成功;失败,那说明已经有别的线程已经先一步获A上的锁了,那么就要升级到自旋或是重量锁。
重入:也就是判断A的Mark Value时,发现有轻量锁,其地址指向的lock record就在T2的栈内,每一次重入,都会在T2的栈上新生成一个lock record,过程和新上锁一样,实际上就形成了一个版本队列,栈上第一个lock record保存的内容是第一次获取A的锁的时候的内容(无锁,或是曾经有偏向锁),第二个lock record保存的就是第一次获取锁之后A上Mark Value的内容。。。
解锁:通过CAS操作将T2栈上的lock record还原到A的Mark Value中,如果操作成功,那么解锁成功,失败则说明有别的线程在竞争A上的锁,已经升级为自旋或是重量锁了。
总结:在没有多线程竞争的情况下,首次加锁或重入加锁的开销都差不多,一个CAS操作,但是一旦出现多线程竞争,就往自旋或是重量锁转变。 -
自适应自旋锁:
任务本身要做的事如果很短,比如就是个计数器,这时如果使用阻塞锁,那么切换线程的开销可能比任务本身还大。
自旋就是为了优化这个问题,让线程执行一个无意义循环来竞争锁,如果竞争不到,继续循环(而不是线程阻塞),直到获取锁,或是达到某一个基于统计的次数(基于JVM运行时的统计,这个次数称为上界,这就是自适应)而仍然没有拿到锁,那就转换为阻塞锁。此过程中线程一直处于RUNNABLE状态,直到任务完成或是转换成阻塞锁,转换为阻塞锁,线程就处于BLOCKED状态。
可以抽象的解释为:线程会先不断尝试竞争锁(有次数限制,上界),超过次数,那么说明资源很紧俏,别老嚷嚷了,认命吧,进入阻塞状态安心等待。
好处:不用第一次失败就进入阻塞队列(可能没有队列,空间优化),失败一定次数了,那么说明资源很紧俏,别老嚷嚷了,嚷嚷也要口水的,不如等资源管理者给你分配更有效(时间优化)。
-
阻塞锁(重量锁,Monitor):
线程竞争锁的时候先尝试一把,如果失败或是锁已经被拿走,那么线程进入BLOCKED状态,并被塞入阻塞队列。等到锁释放,队列中的锁又来打一次群架,成功的做事,失败的老实呆着。
具体的可以参考另外一篇:http://blog.csdn.net/chen77716/article/details/6618779线程的阻塞和唤醒需要CPU从用户态转为核心态,频繁切换的开销还是挺大的。
-
待续
相关推荐
### Java synchronized 关键字详解 #### 一、synchronized关键字简介 `synchronized`是Java语言提供的关键字之一,用于实现线程间的同步控制。通过在方法或代码块上使用`synchronized`,可以确保同一时间只有一个...
"Java 中 synchronized 用法详解" Synchronized 是 Java 语言中用于解决多线程共享数据同步问题的关键字。它可以作为函数的修饰符,也可以作为函数内的语句,用于实现同步方法和同步语句块。在 Java 中,...
Java 中的 synchronized 用法详解 Java 中的 synchronized 关键字是用于解决多线程并发问题的重要工具之一。它可以被用于方法、代码块和变量上,以实现对共享资源的互斥访问控制。本文将对 Java 中的 synchronized ...
在Android开发中,`synchronized`关键字是Java语言中用于实现线程同步的重要工具,它在多线程环境下确保了共享资源的安全访问。本测试案例深入探讨了`synchronized`的使用方法,包括同步单个对象、同步多个对象以及...
Java中的`synchronized`关键字是多线程编程中的一个重要概念,用于控制并发访问共享资源,以保证数据的一致性和完整性。这个关键词提供了互斥锁机制,防止多个线程同时执行同一段代码,确保了线程安全。 一、`...
在Java编程语言中,`synchronized`关键字是一个重要的并发控制机制,用于确保多线程环境下的数据一致性。本文将深入探讨`synchronized`的几种使用示例,包括方法加锁、代码块加锁(针对`this`和对象)以及静态方法...
### volatile与synchronized的区别 #### 一、锁的特性:互斥与可见性 在并发编程中,锁作为实现线程安全的一种手段,其核心作用在于提供两种特性:互斥和可见性。 - **互斥**:互斥是指在任何时刻,只允许一个...
"Java 锁机制 Synchronized" Java 锁机制 Synchronized 是 Java 语言中的一种同步机制,用于解决多线程并发访问共享资源时可能出现的一些问题。 Java 锁机制 Synchronized 的概念 在 Java 中,每个对象都可以被...
在Java多线程编程中,`synchronized`关键字是一个至关重要的工具,用于实现线程间的同步,以确保共享资源的安全访问。本实例大全将全面解析`synchronized`的使用方式,包括同步方法、同步语句块、类锁和对象锁。 ##...
在Java编程语言中,`synchronized`关键字是一个非常重要的并发控制机制,用于保证多线程环境下的数据一致性。本文将深入解析`synchronized`的工作原理、使用方式以及它在并发编程中的重要性。通过分析提供的源码,...
Java中的`synchronized`关键字是多线程编程中的一个重要概念,用于控制并发访问共享资源时的同步机制。在Java中,当多个线程试图同时访问和修改同一块代码或数据时,可能会导致数据不一致的问题。为了解决这个问题,...
### synchronized关键字的深入解析 #### 一、synchronized关键字的重要性 `synchronized`关键字在Java语言中扮演着极其重要的角色,它是实现线程安全的核心手段之一。通过`synchronized`关键字,开发人员可以在多...
《深入理解Java中的synchronized关键字》 在Java编程语言中,`synchronized`关键字是用于实现线程同步的重要工具,它的本质在于确保多线程环境下的数据一致性与安全性。通过`synchronized`,我们可以控制对共享资源...
### Synchronized关键字在Java中的应用 #### 概述 `synchronized`是Java语言中的一个关键字,主要用于实现线程同步,防止多个线程同时访问共享资源而导致的数据不一致问题。通过`synchronized`关键字,开发者可以...
在Java编程语言中,`synchronized`关键字是一个至关重要的概念,它主要用于实现线程同步,以确保多线程环境下的数据一致性与安全性。本篇文章将深入探讨`synchronized`的使用,包括其基本原理、使用方式以及实际应用...
Java中的`synchronized`关键字是多线程编程中用于同步控制的关键元素,它的主要目标是解决并发环境下多个线程对共享资源的访问冲突。在Java中,由于线程共享内存空间,如果没有适当的同步机制,可能会导致数据不一致...
在这个项目中,开发者利用`synchronized`关键字来实现线程同步,确保数据在生产与消费过程中的安全。 `synchronized`是Java中用于实现线程互斥的关键字,它提供了对共享资源的独占访问。当一个线程进入由`...
在Java编程中,synchronized和ReentrantLock都是用于实现线程同步的重要工具,它们在并发控制方面扮演着关键角色。然而,两者之间存在一些显著的区别,这些差异体现在功能、灵活性、性能以及使用场景上。 首先,...
`@synchronized`关键字是Apple提供的一种简便的同步机制,它可以帮助开发者确保在多线程环境下对共享资源进行原子性操作,防止数据竞争问题。本文将深入探讨`@synchronized`的工作原理、特点以及使用时需要注意的...