一、synchronized的使用
(一)、synchronized同步方法
1. “非线程安全”问题存在于“实例变量”中,如果是方法内部的私有变量,则不存在“非线程安全”问题。
2. 如果多个线程共同访问1个对象中的实例变量,则有可能出现“非线程安全”问题。
3. synchronized取得的锁都是对象锁,而不是把一段代码或方法当做锁。因此在多线程访问同一个对象时,哪个线程先执行synchronized关键字的方法,哪个线程就持有该方法所属对象的锁lock,其他线程只能呈等待状态。
但如果多个线程访问多个对象,则JVM会创建多个锁。
4. 调用关键字synchronized声明的方法一定是排队运行的。另外只有共享资源的读写访问才需要同步化,如果不是共享资源,就没有同步化的必要。
5. 脏读。当A线程调用anyObject对象加入synchronized关键字的X方法时,A线程就获得了X方法锁,更准确地讲,是获得了对象的锁,所以其他线程必须等A线程执行完毕才可以调用X方法,但B线程可以随意调用其他的非synchronized关键字的同步方法。
6. synchronized锁重入。使用synchronized时,当一个线程得到一个对象锁后,再次请求此对象锁时,是可以再次得到该对象的锁的。
7. 当一个线程执行的代码出现异常时,其所持有的锁会自动释放。
8. 同步不可以继承。如果父类方法使用了关键字synchronized,那么子类方法不会继承synchronized,如果子类需要同步,还需要在子类方法中添加synchronized。

(二)、synchronized同步代码块
1. 同一个方法中,不在synchronized块中的就是异步执行,在synchronized块中的就是同步执行。
2. 当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对同一个object中所有其他synchronized(this)同步代码块的访问将被阻塞,这是因为synchronized使用的是“对象监视器”。
3. 和synchronized方法一样,synchronized(this)代码块也是锁定当前对象。
4. java还支持对“任意对象”作为“对象监视器”来实现同步的功能。这个任意对象大多数是实例变量及方法的参数,使用格式为:synchronized(非this对象x),此时将x对象本身作为“对象监视器”
锁非this对象的优点:如果在一个类中有很多个synchronized方法,这时虽然能实现同步,但会受到阻塞,所以影响运行效率;但如果使用同步代码块锁非this对象,则synchronized(非this对象x)代码块中的程序与同步方法是异步的,不与其他锁this同步方法争抢this锁,可以大大提高运行效率。
5. synchronized还可以应用在static静态方法上,如果这样写,就是对当前的*.java文件对应的class类进行加锁。
跟synchronized加到非static方法上的区别:synchronized加到static静态方法上,是给Class类上锁;而synchronized加到非static静态方法上,是给对象上锁。
6. 由于JVM具有String常量池缓存的功能,因此在大多数情况下,同步synchronized代码块都不使用String作为锁对象:synchronized(string),而改用其他的,比如new Object实例化一个Object对象,但它并不放入缓存中。

以上方法的具体代码例子可以参考《java多线程编程核心技术》

二、synchronized的实现原理

目前在Java中存在两种锁机制:synchronized和Lock
synchronized实现同步的基础:Java中每一个对象都可以作为锁,具体表现为以下3种方式:(Synchronized锁, 锁住的是对象。)
1. 对于普通同步方法,锁是当前实例对象
2. 对于静态同步方法,锁是当前类的class对象
3. 对于同步方法块,锁是synchronized括号里配置的对象
synchronized用的锁是存在java对象头里的。重量级锁、轻量级锁和偏向锁之间的转换:

Synchronized同步块和同步方法在实现上的区别:

在下面的例子中,使用了同步块和同步方法,通过使用javap工具查看生成的class文件信息,来分析synchronized关键字的实现细节。

public class Synchronized {
public static void main(String[] args) {
// 对Synchronized Class对象进行加锁
synchronized (Synchronized.class) { }
// 静态同步方法,对Synchronized Class对象进行加锁
m();
} public static synchronized void m() {
}
}

在synchronized.class的同级目录下执行:javap -v synchronized.class,部分输出如下:

说明:

  public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC //方法修饰符,表示public static
Code:
stack=2, locals=1, args_size=1
0: ldc #1 // class testnew/Synchronized
2: dup
3: monitorenter // monitorenter:监视器进入,获取锁
4: monitorexit // monitorexit: 监视器退出,释放锁
5: invokestatic #16 // Method m:()V
8: return public static synchronized void m();
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED //方法修饰符,表示public static synchronized
Code:
stack=0, locals=0, args_size=0
0: return

对于同步块的实现使用了monitorenter和monitorexit指令,而同步方法则是依靠方法修饰符上的ACC_SYNCHRONIZED来完成的。无论采用哪种方法,其本质是对一个对象的监视器(monitor)进行获取,而这个获取过程是排他的,也就是同一个时刻只能有一个线程获取到由synchronized所保护对象的监视器。

任意一个对象都拥有自己的监视器,当这个对象由同步块或者这个对象的同步方法调用时,执行方法的线程必须先获取到该对象的监视器才能进入同步块或者同步方法,而没有获取到监视器(执行该方法)的线程将会被阻塞在同步块和同步方法的入口处,进入BLOCKED状态。

下图描述了对象、对象的监视器、同步队列和执行线程之间的关系。

可以看出,任意线程对Object(Object由synchronized保护)的方法,首先要获得Object的监视器。如果获取失败,线程进入同步队列,线程状态变为BLOCKED。当访问Object的前驱(获得了锁的线程)释放了锁,则该释放操作唤醒阻塞在同步队列总的线程,使其重新尝试对监视器的获取。

相关阅读:java中的锁分类

参考:

《Java并发编程的艺术》

Java中的锁机制 synchronized & 偏向锁 & 轻量级锁 & 重量级锁 & 各自优缺点及场景 & AtomicReference

对synchronized的一点理解的更多相关文章

  1. java 多线程 Synchronized方法和方法块 synchronized(this)和synchronized(object)的理解

    synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块. 1. synchronized 方法:通过在方法声明中加入 synchronized ...

  2. opencv笔记5:频域和空域的一点理解

    time:2015年10月06日 星期二 12时14分51秒 # opencv笔记5:频域和空域的一点理解 空间域和频率域 傅立叶变换是f(t)乘以正弦项的展开,正弦项的频率由u(其实是miu)的值决 ...

  3. 对socket的一点理解笔记

    需要学web service,但是在视频中讲解到了socket套接字编程.以前貌似课上老师有提过,只是没用到也感觉乏味.现在遇到,自己看了些博客和资料.记录一点理解,不知正确与否. 首先说这个名字,叫 ...

  4. iOS 的一点理解(一) 代理delegate

    做了一年的iOS,想记录自己对知识点的一点理解. 第一篇,想记录一下iOS中delegate(委托,也有人称作代理)的理解吧. 故名思议,delegate就是代理的含义, 一件事情自己不方便做,然后交 ...

  5. 关于web开发的一点理解

    对于web开发上的一点理解 1 宏观上的一点理解 网页从请求第地址 到获得页面的过程:从客户端(浏览器)通过地址 从soket把请求报文封装发往服务端   服务端通过解析报文并处理报文最后把处理的结果 ...

  6. angular.js的一点理解

    对angular.js的一点理解 2015-01-14 13:18 by MrGeorgeZhao, 317 阅读, 4 评论, 收藏, 编辑 最近一直在学习angular.js.不得不说和jquer ...

  7. RxSwift 入坑好多天 - 终于有了一点理解

    一.前言 江湖上都在说现在就要赶紧学 swift 了,即将是 swift 的天下了.在 api 变化不大的情况下,swift 作为一门新的语言,集众家之所长,普通编码确实比 oc 要好用的多了 老早就 ...

  8. rt-thread中动态内存分配之小内存管理模块方法的一点理解

    @2019-01-18 [小记] rt-thread中动态内存分配之小内存管理模块方法的一点理解 > 内存初始化后的布局示意 lfree指向内存空闲区首地址 /** * @ingroup Sys ...

  9. rt-thread中软件定时器组件超时界限的一点理解

    @2019-01-15 [小记] 对 rt-thread 中的软件定时器组件中超时界限的一点理解 rt_thread_timer_entry(void *parameter)函数中if ((next_ ...

随机推荐

  1. js简单时间比较的方法(转)

    //时间比较(yyyy-MM-dd) function compareDate(startDate, endDate) {   var arrStart = startDate.split(" ...

  2. JUC——线程同步辅助工具类(Semaphore,CountDownLatch,CyclicBarrier)

    锁的机制从整体的运行转态来讲核心就是:阻塞,解除阻塞,但是如果仅仅是这点功能,那么JUC并不能称为一个优秀的线程开发框架,然而是因为在juc里面提供了大量方便的同步工具辅助类. Semaphore信号 ...

  3. python继承与多继承

    1.类与对象里的父类与子类(继承): 类的继承主要是指自子类对于之前父类的方法的继承,如果子类里面写了父类里的方法,则它会将父类里的方法覆盖掉,从而不能再调用到父类的方法. 2.为了解决父类与子类里的 ...

  4. Python之NMAP详解

    一.NMAP简介 NMap,也就是Network Mapper,最早是Linux下的网络扫描和嗅探工具包. nmap是一个网络连接端扫描软件,用来扫描网上电脑开放的网络连接端.确定哪些服务运行在哪些连 ...

  5. 学习python,第一篇

    name = "danie" name2 = name print(name,name2) name = "itxpl" print(name,name2) 结 ...

  6. 04-matplotlib-柱形图

    import numpy as np import matplotlib.pyplot as plt # 柱形图 # 例一 N =5 y = [15,28,10,30,25] index = np.a ...

  7. nginx 在ubuntu上使用笔记(绑定域名)

    1. 重启nginx的两个语句: sudo service nginx restart sudo nginx -s reload 2. nginx配置文件路径: etc/nginx/ 尤其是 site ...

  8. Python序列之列表 (list)

    作者博文地址:http://www.cnblogs.com/spiritman/ 列表是Python中最基本的数据结构,是Python最常用的数据类型.Python列表是任意对象的有序集合,通过索引访 ...

  9. Vue 入门之数据绑定

    什么是双向绑定? Vue 框架很核心的功能就是双向的数据绑定. 双向是指:HTML 标签数据 绑定到 Vue 对象,另外反方向数据也是绑定的.通俗点说就是,Vue 对象的改变会直接影响到 HTML 的 ...

  10. iOS静态库.a总结(2017.1.24增加脚本打包方法)

    修改于:2017.1.24 1.什么是库? 库是程序代码的集合,是共享程序代码的一种方式 2.根据源代码的公开情况,库可以分为2种类型 a.开源库 公开源代码,能看到具体实现 ,比如SDWebImag ...