在Java编程中,为了保证线程安全,有3种不同的思路
1、互斥同步:包括synchronized和lock等。

2、非阻塞同步:如AtomicInteger的increaseAndGet()方法等。

3、无同步:如ThreadLocal方案。

本文介绍使用synchronized实现同步的方法。

1、修饰方法
synchronized static方法:锁加在类上;synchronized 普通方法:锁加在对象上。由此可以知道:
  • 当一个线程正在访问一个对象的synchronized方法,那么其他线程不能访问该对象的其他synchronized方法。
  • 当一个线程正在访问一个对象的synchronized方法,那么其他线程能访问该对象的非synchronized方法。
  • 如果一个线程A需要访问对象object1的synchronized方法fun1,另外一个线程B需要访问对象object2的synchronized方法fun1,即使object1和object2是同一类型,也不会产生线程安全问题,因为他们访问的是不同的对象,所以不存在互斥问题。
  • 如果一个线程执行一个对象的synchronized普通方法,另外一个线程需要执行这个对象所属类的synchronized static方法,此时不会发生互斥现象,因为访问synchronized static方法占用的是类锁,而访问synchronized普通方法占用的是对象锁,所以不存在互斥问题。
 
2、修饰代码块:代码如下所示。
synchronized(synObject) {
......
}
当在某个线程中执行这段代码块,该线程会获取对象synObject的锁,从而使得其他线程无法同时访问该代码块。synObject可以是this,代表获取当前对象的锁,也可以是类中的一个属性,代表获取该属性的锁。修饰代码块与修饰方法相比,更加灵活,可以选择方法中需要同步的代码块进行同步。
无论synObject是不是this,对于被同步的对象而言,不同方法之间的相互影响,类似于1中描述:如果是某对象的一个同步代码块被执行,那么该对象的所有同步代码块、同步方法,都要等该代码块执行完才能够执行;同步方法与之类似。
 
3、synchronized还可以修饰类,如下所示。
synchronized(xxx.class) {
......
}
就像synchronized(syncObject)与synchronized普通方法作用类似,synchronized(xx.class)与synchronized static方法作用类似,是加在类上的锁。同样,synchronized(xx.class)与synchronized static方法,如果是对同一类的锁,也会互斥。
 
4、对于synchronized方法或者synchronized代码块,当出现异常时,JVM会自动释放当前线程占用的锁,因此不会由于异常导致出现死锁现象。
 
5、原理解析:在Java中,每一个对象都拥有一个锁标记(monitor),多线程同时访问某个对象时,线程只有获取了该对象的锁才能访问。每个类应该也有这个标记。这就解释了为什么同一个对象的不同synchronized方法和synchronized代码块是互斥的,因为他们共用一个锁;同样解释了类层面的互斥。
对于synchronized代码块,对应的字节码是monitorenter和monitorexit;synchronized方法对应的字节码仍然是synchronized。monitorenter和monitorexit字节码指令需要reference类型的参数,当Java程序中没有明确指定时,JVM会取实例对象或Class对象作为锁对象。
注意:synchronized同步块对同一条线程来说是可重入的,不会出现自己把自己锁死的问题。
 
6、同步块在已进入的线程执行完之前,会阻塞后面其他线程的进入。而Java的线程是映射到操作系统的原生线程之上的,如果要阻塞或唤醒一个线程,都需要操作系统来帮忙完成,这就需要从用户态转换到核心态中,因此状态转换需要耗费很多的处理器时间。对于代码简单的同步块(如被synchronized修饰的getter()或setter()方法),状态转换消耗的时间有可能比用户代码执行的时间还要长。所以synchronized是Java语言中一个重量级(Heavyweight)的操作,有经验的程序员都会在确实必要的情况下才使用这种操作。而虚拟机本身也会进行一些优化,譬如在通知操作系统阻塞线程之前加入一段自旋等待过程,避免频繁地切入到核心态之中。
 
 

Java并发编程之synchronized的更多相关文章

  1. Java并发编程之synchronized关键字

    整理一下synchronized关键字相关的知识点. 在多线程并发编程中synchronized扮演着相当重要的角色,synchronized关键字是用来控制线程同步的,可以保证在同一个时刻,只有一个 ...

  2. Java并发编程之CAS

    CAS(Compare and swap)比较和替换是设计并发算法时用到的一种技术.简单来说,比较和替换是使用一个期望值和一个变量的当前值进行比较,如果当前变量的值与我们期望的值相等,就使用一个新值替 ...

  3. Java并发编程之CAS第一篇-什么是CAS

    Java并发编程之CAS第一篇-什么是CAS 通过前面几篇的学习,我们对并发编程两个高频知识点了解了其中的一个—volatitl.从这一篇文章开始,我们将要学习另一个知识点—CAS.本篇是<凯哥 ...

  4. Java并发编程之CAS二源码追根溯源

    Java并发编程之CAS二源码追根溯源 在上一篇文章中,我们知道了什么是CAS以及CAS的执行流程,在本篇文章中,我们将跟着源码一步一步的查看CAS最底层实现原理. 本篇是<凯哥(凯哥Java: ...

  5. Java并发编程之CAS第三篇-CAS的缺点及解决办法

    Java并发编程之CAS第三篇-CAS的缺点 通过前两篇的文章介绍,我们知道了CAS是什么以及查看源码了解CAS原理.那么在多线程并发环境中,的缺点是什么呢?这篇文章我们就来讨论讨论 本篇是<凯 ...

  6. Java并发编程之set集合的线程安全类你知道吗

    Java并发编程之-set集合的线程安全类 Java中set集合怎么保证线程安全,这种方式你知道吗? 在Java中set集合是 本篇是<凯哥(凯哥Java:kagejava)并发编程学习> ...

  7. Java并发编程之Lock

    重入锁ReentrantLock 可以代替synchronized, 但synchronized更灵活. 但是, 必须必须必须要手动释放锁. try { lock.lock(); } finally ...

  8. Java并发编程之volatile的应用

    在多线程的并发编程中synchronized和volatile都扮演着重要的角色.volatile是轻量级的synchronized,它在多处理器的开发中保证了共享变量的可见性,可见性的意思是当一个线 ...

  9. Java 并发编程之 Condition 接口

    本文部分摘自<Java 并发编程的艺术> 概述 任意一个 Java 对象,都拥有一个监视器方法,主要包括 wait().wait(long timeout).notify() 以及 not ...

随机推荐

  1. NodeJs之fs的读写删移监

    NodeJs版本:4.4.4 fs 文件系统模块是一个封装了标准的 POSIX 文件 I/O 操作的集合.Node.js 文件系统(fs 模块)模块中的方法均有异步和同步版本. 图片的复制与粘贴 创建 ...

  2. [ext4]磁盘布局 - inode bitmap & table

    在[磁盘布局 group部分]已经介绍过ext4的整体布局,其中存在两个与inode有关的名称:inode bitmap和inode table. Inode bitmap,用于表示inode tab ...

  3. PHP填补数字前后的0

    PHP数字填补0 经常会遇到这样的问题: 自然数字是0,1,2,3...而我们需要的却是满足多少多少位数的数字,如:001,002. 在ID,编号,学号中我们会经常用到补全前面或者后面的空位(一般为前 ...

  4. #include<> 和#include“”的区别

    1.< >引用的是编译器的类库路径里面的头文件2."    "引用的是程序目录的相对路径中的头文件,在程序目录的相对路径中找不到该头文件时会继续在类库路径里搜寻该头文件 ...

  5. godot新手中文系列教程1-打包安卓

    国内godot qq群 302924317 我也是个新手,可以进群多多交流. 我想要吐槽一下,官方文档有点陈旧,细节缺乏,所以某些时候不要相信官方文档,可以向我们可爱的群友提问,他们一定很乐意回答. ...

  6. Oracle中碰到的函数和关键字收集

    一.时间处理函数 trunc(sysdate) 返回日期 to_date() to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') to_number() 转为数字 二.字 ...

  7. Jfinal中Db类的的使用

    Jfinal提供了两种操作数据库的组件,分别是Model类和DB类,可以极大地减少代码量,提高开发效率. Db类提供了在Model类之外更丰富的的数据库操作能力,使用Db类以及嵌套的Record类时, ...

  8. iOS 使用 UIMenuController 且不隐藏键盘的方法

    iOS 使用 UIMenuController 且不隐藏键盘的方法 在键盘显示的时候使用 UIMenuController 弹出菜单,保持键盘显示且可输入的状态. 实现方法有 修改响应链(推荐) 遵循 ...

  9. 设计模式的征途—6.建造者(Builder)模式

    建造者模式又称为生成器模式,它是一种较为复杂.使用频率也相对较低的创建型模式.建造者模式为客户端返回的不是一个简单的产品,而是一个由多个部件组成的复杂产品.因为,没有人买车会只买一个方向盘或者轮胎,大 ...

  10. sscanf( )函数初体验

    解析字符串,将%格式的内容,存储到后面的参数中 %% - 返回一个百分号 % %c - ASCII 值对应的字符 %d - 包含正负号的十进制数(负数.0.正数) %e - 使用小写的科学计数法(例如 ...