Java synchronized的原理解析
开始
类有一个特性叫封装,如果一个类,所有的field都是private的,而且没有任何的method,那么这个类就像是四面围墙+天罗地网,没有门。看起来就是一个封闭的箱子,外面的进不来,里面的出不去,一般来说,这样的类是没用的。
1. 给一个代码块上锁
synchronized(obj){
// some code...
}
这个用法就是使用了obj的锁,来锁定一个代码块。
publicsynchronizedvoid aMethod(){
// some code...
}
这个时候它使用的是当前实例this的锁,相当于下面的模式:
publicvoid aMethod(){
synchronized(this){
// some code...
}
}
2. 两个代码块的互斥
class SyncData {
public void do1() {
synchronized(this) {
for (int i=0; i < 4; i++) {
System.out.println(Thread.currentThread().getName() + "-do1-" + i);
try{
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void do2() {
synchronized(this) {
for (int i=0; i < 4; i++) {
System.out.println(Thread.currentThread().getName() + "-do2-" + i);
try{
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
创建1个SyncData的实例,开启2个线程,一个线程调用实例的do1方法,另一个线程调用实例的do2方法,你会看到他们之间是互斥的——即使2个线程访问的是实例的不同的方法,依然不能同时访问。因为决定是否可以同时访问的不再是门,而是锁。只要使用的是相同的对象锁,就会互斥访问。
3. 锁的识别
class SyncData {
private Object lock = new byte[0];
public void do1() {
synchronized(lock) {
for (int i=0; i < 4; i++) {
System.out.println(Thread.currentThread().getName() + "-do1-" + i);
try{
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
思考下面的代码是否能起到互斥访问的作用:
class SyncData {
public void do1() {
Object lock = new byte[0];
synchronized(lock) {
for (int i=0; i < 4; i++) {
System.out.println(Thread.currentThread().getName() + "-do1-" + i);
try{
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
这个是不能起到互斥作用的,因为每一次调用,局部变量lock都是不同的实例。也就是说,synchronized使用的锁总是变化的。所以我们再补充一点:只有使用相同的对象锁,才能互斥访问。所以识别所使用的锁,是很重要的。
class SyncData {
public void do1() {
synchronized(this) {
for (int i=0; i < 4; i++) {
System.out.println(Thread.currentThread().getName() + "-do1-" + i);
try{
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
创建2个实例,分别交给2个线程中的1个去访问,能互斥吗?
class SyncData {
public void do1() {
synchronized(this.getClass()) {
for (int i=0; i < 4; i++) {
System.out.println(Thread.currentThread().getName() + "-do1-" + i);
try{
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
可以互斥,不管一个类有多少个实例,它们调用getClass()返回的结果都是同一个实例。
总结
- 任何对象实例都有一把内部锁,只有一把。
- 相同的对象锁是互斥访问的充要条件。
- 一个类的实例,可能被多个线程并发访问,才考虑同步控制。
- 在1的前提下,只有会导致数据状态出现一段时间的不一致,相关的代码片段才需要同步控制。
- 在2的前提下,只有两块代码会相互干扰时,才必须使用同一把对象锁,来实现互斥;如果相互之间没有影响,建议使用不同的对象锁,以保持并发性能。
- 在不能确认数据状态是否会不一致的情况下,按照会不一致的情况考虑
- 在不能确认两块代码是否有干扰的情况下,按照会有干扰的情况考虑
参考
- Java中Synchronized的用法
介绍了使用synchronized的几种方式,以及相互的区别,写的很好,建议也看一下,相互印证。
Java synchronized的原理解析的更多相关文章
- java线程池原理解析
五一假期大雄看了一本<java并发编程艺术>,了解了线程池的基本工作流程,竟然发现线程池工作原理和互联网公司运作模式十分相似. 线程池处理流程 原理解析 互联网公司与线程池的关系 这里用一 ...
- 【Java并发编程】24、Synchronized实现原理解析
一.概述 我们知道在JDK1.5之前synchronized是一个重量级锁,相对于j.u.c.Lock,它会显得那么笨重,以至于我们认为它不是那么的高效而慢慢摒弃它. 不过,随着后续Java版本更新对 ...
- Java Synchronized的原理
我们先通过反编译下面的代码来看看Synchronized是如何实现对代码块进行同步的: public class SynchronizedDemo{ public void method(){ syn ...
- Java synchronized实现原理总结和偏量锁、轻量锁、重量锁、自旋锁
synchronized实现同步的基础:Java中的每一个对象都可以作为锁.具体表现为以下3种形式. 对于普通同步方法,锁是当前实例对象(this). 对于静态同步方法,锁是当前类的Class对象. ...
- java synchronized 的原理。
synchronized的作用大概分为三种: 1.确保多线程互斥的访问多线程代码.2.保证变量的可见性.3.防止指令重排序. 那么synchronized 是如何实现这些功能的. public cla ...
- java synchronized 关键字原理
Synchronized 关键字是解决并发问题常用解决方案,有以下三种使用方式: 同步普通方法,锁的是当前对象.同步静态方法,锁的是当前 Class 对象.同步块,锁的是 {} 中的对象. 实现原理: ...
- Java反序列化漏洞原理解析(案例未完善后续补充)
序列化与反序列化 序列化用途:方便于对象在网络中的传输和存储 java的反序列化 序列化就是将对象转换为流,利于储存和传输的格式 反序列化与序列化相反,将流转换为对象 例如:json序列化.XML序列 ...
- Java并发之synchronized关键字深度解析(二)
前言 本文继续[Java并发之synchronized关键字深度解析(一)]一文而来,着重介绍synchronized几种锁的特性. 一.对象头结构及锁状态标识 synchronized关键字是如何实 ...
- Java并发包JUC核心原理解析
CS-LogN思维导图:记录CS基础 面试题 开源地址:https://github.com/FISHers6/CS-LogN JUC 分类 线程管理 线程池相关类 Executor.Executor ...
随机推荐
- 基础知识:BT1120
今天谈点我所理解的BT1120协议. BT1120是高清晰度电视 (HDTV) 演播室信号数字接口,首先说一下接口标准里面的概念,然后谈谈自己的理解,写这个文章的目的就是解释给自己听的,所以都是一些白 ...
- docker-compose写法收集
version: '3.3' services: php: image: docker.ksyun.com/php7.:latest volumes: - ./env/log/apps:/data/l ...
- java网络传输数据
网络文件传输的问题,实际也是一种IO读写的基本问题.对于网络的文件数据写入到服务器的进程中,然后把进程中的网络IO系统传递到客户机,这个阶段,数据以字节流的形式保存.当该字节流被客户进程接受后,客户进 ...
- easyUI导出数据
easyUI导出数据模式 后台: //导出数据 public function index_doExport() { $search['diqu']=$_POST['diqu']; $search[' ...
- python学习笔记(十三)之lambda表达式
lambda表达式: 用法 lambda x : 2 * x + 1 其中:前面是参数,后面是返回值. >>> def ds(x): ... return 2 * x + 1 ... ...
- POJ 3233 Matrix Power Series (矩阵快速幂)
题目链接 Description Given a n × n matrix A and a positive integer k, find the sum S = A + A^2 + A^3 + - ...
- koa源码阅读[1]-koa与koa-compose
接上次挖的坑,对koa2.x相关的源码进行分析 第一篇.不得不说,koa是一个很轻量.很优雅的http框架,尤其是在2.x以后移除了co的引入,使其代码变得更为清晰. express和koa同为一批人 ...
- dlmalloc(一)【转】
转自:http://blog.csdn.net/ycnian/article/details/12971863 我们写过很多C程序了,经常会分配内存.记得刚学C语言时老师说过,可以向两个地方申请内存: ...
- python基础===如何在列表,字典,集合中根据条件筛选数据
#常见的操作如下: data = [1, 5, -3, -2, 6, 0, 9] res = [] for x in data: if x>=0: res.append(x) print(res ...
- UVA 1103 How Many O's?
题目链接:UVA-11038 题意为给定n和m,求n和m之间(包含)的所有数包含的0的个数. 思路是,用cal(x)表示小于等于x的数包含的0的个数.则答案为cal(n)-cal(m-1). 再把求c ...