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 ... 
随机推荐
- 课程设计——利用信号量实现读-写者问题(JAVA)
			package cn.Douzi.ReadWriter; import java.util.Scanner; public class ReadWrite { static public int co ... 
- 【BZOJ】1834 [ZJOI2010]network 网络扩容
			[算法]网络流-最大流+最小费用最大流(费用流) [题解] 第一问跑最大流. 第二问: 原始边相当于费用为0的边,再原图(跑过最大流的图)基础上添加带费用的边,容量为k(相当于inf). 第一问最大流 ... 
- 【HDU】6110 路径交(2017百度之星) 线段树+RMQ-LCA+树链的交
			[题目]2017"百度之星"程序设计大赛 - 初赛(A) [题意]给定n个点的带边权树,m条编号1~m的路径,Q次询问编号区间[L,R]所有链的交集的长度.n<=500000 ... 
- 【BZOJ】3771: Triple FTT+生成函数
			[题意]给定n个物品,价值为$a_i$,物品价格互不相同,求选一个或两个或三个的价值为x的方案数,输出所有存在的x和对应方案数.$ai<=40000$. [算法]生成函数+FFT [题解]要求价 ... 
- 基本控件文档-UITextField属性---iOS-Apple苹果官方文档翻译
			本系列所有开发文档翻译链接地址:iOS7开发-Apple苹果iPhone开发Xcode官方文档翻译PDF下载地址 //转载请注明出处--本文永久链接:http://www.cnblogs.com/Ch ... 
- c语言学习笔记.关键字.存储类型关键字等
			关键字const 1.修饰变量. 修饰的对象为常量,只读. 2.修饰指针. const 也可以和指针变量一起使用,这样可以限制指针变量本身,也可以限制指针指向的数据. const 离变量名近就是用来修 ... 
- JS设计模式——3.封装与信息隐藏
			封装.信息隐藏与接口的关系 信息隐藏是目的,封装是手段. 接口提供了一份记载着可供公共访问的方法的契约.它定义了两个对象间可以具有的关系.只要接口不变,这个关系的双方都是可以替换的. 一个理想的软件系 ... 
- Warning: Permanently added the RSA host key for IP address '192.30.253.113' to the list of known hosts. Permission denied (publickey). fatal: Could not read from remote repository.  Please make sure y
			这个应该是很多github新手经常出错的问题,这个就是没有在你github上添加一个公钥. 下面就直接说步骤: 1 可以用 ssh -T git@github.com去测试一下 图上可以明显看出缺少了 ... 
- 【Eclipse】Elipse自定义library库并导入项目
			1.定义像JRE System Library之类的库 (1)点击UserLibrary (2)如果没有就点击new新建一个user library,否则进行4 (3)向user library添加 ... 
- php中的转义函数
			<?php parse_url 解析URL, 返回各组成部分 urlencode/urldecode url编码/解码 htmlentities 将字符串转化为html实体 htmlentiti ... 
