重新认识synchronized(上)
synchronized在JDK5之前一直被称为重量级锁,是一个较为鸡肋的设计,而在JDK6对synchronized内在机制进行了大量显著的优化,加入了CAS,轻量级锁和偏向锁的功能,性能上已经跟ReentrantLock相差无几,而且synchronized在使用上更加简单,不易出错(避免哲学家就餐问题造成的死锁),因此如果仅仅是为了实现互斥,而不需要使用基于Lock的附加属性(中断、条件等),推荐优先使用synchronized。
synchronized用法
synchronized有同步方法和同步语句块两种形式,分锁定对象和作用域两个维度,当锁定的对象进入作用域时,互斥才会生效。一个线程访问拥有相同锁定对象时,进入作用域时必须以串行方式进行。修饰的对象有:修饰普通方法(又称为同步方法),修饰静态方法,修饰对象实例,修饰class literals(类名称字面常量)。
修饰普通方法
又称同步方法,锁定的是调用这个同步方法对象。一个线程访问实例对象中的synchronized代码块时,其他试图访问该对象synchronized修饰的区域的线程将阻塞。同一个对象共享一把锁,同一时间只能有一个synchronized区域可以获得锁,可以称为对象锁。需要注意两点:(1)作用只会在同一个实例上,(2)对象中的所有synchronized修饰的区域。例如:对于fooA对象,线程t1,t2访问methodA是互斥的,线程t1,t2分别访问methodA,methodB同样是互斥的;当访问methodA时,methodB 不可以访问,methodC可以访问。
public class Foo implements Runnable {
public static synchronized void methodA() {
//TODO
} public static synchronized void methodB() {
//TODO
} public void methodC() {
//TODO
} public static void main(String[] args) {
Foo fooA = new Foo();
Foo fooB = new Foo(); Thread t1 = new Thread(fooA, "t1");
Thread t2 = new Thread(fooB, "t2");
t1.start();
t2.start();
}
}
修饰静态方法
锁定是静态方法所属的类,此时该类共用一把锁,可以称为类锁。一个线程访问synchronized静态方法时,其他试图访问该类synchronized修饰的区域的线程都将阻塞,而非synchronized修饰的区域不会阻塞。修饰静态方法是修饰普通方法的变种版,前者锁定该类(跟对象没关系),后者指锁定当前对象。例如:线程t1,t2分别访问methodA,methodB同样是互斥的。
同步语句块
修饰对象实例的情况与修饰普通方法一致,区别在于只有线程进入同步语句块时,才是互斥的。而修饰class literals(类名称字面常量)与修饰静态方法一致。例如:methodD锁定的是当前对象,而methodE中的synchronized锁定的是Foo类的所有对象。
public class Foo {
public void methodD() {
synchronized (this) {
//TODO
}
} public void methodE() {
synchronized (Foo.class) {
//TODO
}
}
}
synchronized机制
synchronized是Java为线程间通信提供的一种方式,synchronized的这种同步机制是互斥锁机制。实现互斥的方式有:临界区(Critical Section),互斥量(Mutex),信号量(Semaphores)和事件(Event)。
synchronized是采用临界区的方式实现互斥的,通过对多线程的串行化来访问公共资源或一段代码,保证同一时刻只有一个线程能访问临界区内共享数据。如果多个线程试图同时访问临界区,其中一个线程抢占临界区后,其他试图访问该临界区的线程将会挂起,直到进入临界区的线程。举个栗子,会议室资源相对紧张,有多个团队都需要使用会议室,这时就看哪个团队的迅速了。当这个团队抢占到会议室后,就会挂起“正在会议中”的提示牌,其他需要使用会议室的人看到会等待,直到当前使用会议室的团队使用完,移走“正在会议中”的提示牌。
synchronized同时保证了可见性。互斥锁释放后,确保一个线程修改的对象状态,对其他线程是可见的,即在随后获取锁的线程中保证获得最新共享资源的状态。synchronized互斥锁是通过监视器(Monitor)实现的。
什么是监视器(Monitor)
监视器是一种同步机制。 通过获取和释放锁,保证线程间可以互斥地操作共享资源,同一时间最多只有一个线程占用监视器,即互斥(mutex);采用条件变量(Condition Variables),允许线程阻塞和等待另一个线程发送信号的方法弥补互斥锁的不足,这就是监视器的互斥和协作。
当多线程同时访问一段同步代码时,新请求的线程会首先加入到Entry Set集合中,通过竞争(compete)方式,同一时间只有一个线程可以竞争成功并获取监视器,进入The Owner。获取监视器的线程调用wait()后就会释放监视器,并进入Wait Set集合中等待满足条件时被唤醒。无论是acquire还是release都是使用原子指令如test-and-set、compare-and-set来实现自旋锁来保证对关键段的访问。java-monitor
参考
重新认识synchronized(上)的更多相关文章
- 并发和多线程-八面玲珑的synchronized
上篇<并发和多线程-说说面试常考平时少用的volatile>主要介绍的是volatile的可见性.原子性等特性,同时也通过一些实例简单与synchronized做了对比. 相比较volat ...
- synchronized的功能拓展:重入锁(读书笔记)
重入锁可以完全代替synchronized关键字.在JDK5.0的早期版本中,重入锁的性能远远好于synchronized,但是从JDK6.0开始.JDK在synchronized上做了大量的优化. ...
- 线程互斥synchronized
/** * * 线程互斥,采用synchronized关键字可以实现线程与线程之间的互斥,要注意的是在synchronized上的对象要是同一个,才可以 * 保证在同一时刻,只有一个线程可以执行syn ...
- 多线程编程学习四(Lock 的使用).
一.前言 本文要介绍使用Java5中 Lock 对象,同样也能实现同步的效果,而且在使用上更加方便.灵活,主要包括 ReentrantLock 类的使用和ReentrantReadWriteLock ...
- Java面试准备之多线程
什么叫线程安全?举例说明 多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或者协同,这个类都能表现出正确的行为,那么就称这个类是线程 ...
- Java基础知识盘点(三)- 线程篇
创建线程的方式及实现 一.继承Thread类创建线程类 1.定义Thread的子类,并重写run方法,因为该方法的方法体就是代表了线程要完成的任务,因此run方法又叫做执行体. 2.创建Thread子 ...
- JDK并发工具之同步控制
一.synchronized的功能扩展:重入锁(java.util.concurrent.locks.ReentrantLock) 重入锁可以完全替代synchronized关键字.在JDK 5.0的 ...
- 《Java并发编程的艺术》留给自己以后看的笔记
<Java并发编程的艺术>这本书特别好,和<深入了解JAVA虚拟机>有一拼,建议做java的都看看,下面全部都是复制书中的部分内容,主要目的是做个笔记,方便以后遇到问题能找到. ...
- 实验11——java线程模拟卖票
package cn.tedu.demo; /** * @author 赵瑞鑫 E-mail:1922250303@qq.com * @version 1.0 * @创建时间:2020年7月31日 下 ...
- 《Java并发编程的艺术》笔记
第1章 并发编程的挑战 1.1 上下文切换 CPU通过时间片分配算法来循环执行任务,任务从保存到再加载的过程就是一次上下文切换. 减少上下文切换的方法有4种:无锁并发编程.CAS算法.使用最少线程.使 ...
随机推荐
- 调整JVM堆内存解决OutOfMemoryError
今天在用 processing(http://zh.wikipedia.org/wiki/Processing) 编写处理 midi 文件的程序的时候,遇到了一个问题.程序主要是读取分析 midi , ...
- java项目 里的DAO,model,service, IMPL含义
在一般工程中 基本上都会出现上述的字眼首先 DAO 提供了应用程序与数据库之间的操作规范 和操作 用于通常数据库的增删查改 一般如果使用框架 都是由框架自动生成,提高访问效率和便于快速开发.hiber ...
- Asp.net WebAPI 使用流下载文件注意事项
public HttpResponseMessage Post(string version, string environment, string filetype) { var path = @& ...
- Codeforces 893E Counting Arrays:dp + 线性筛 + 分解质因数 + 组合数结论
题目链接:http://codeforces.com/problemset/problem/893/E 题意: 共q组数据(q <= 10^5),每组数据给定x,y(x,y <= 10^6 ...
- mogon操作数据库
返回的本来就是promise redis是内存数据库,更适合放session等一些东西.而mongo不是.
- [Gym-101512C] 凸包+最远点对
找最大的四边形或者三角形面积,先求凸包,然后枚举两个点,再通过旋转,找最大的另两个点 #include<bits/stdc++.h> #define fi first #define se ...
- Hive group by实现-就是word 统计
准备数据 SELECT uid, SUM(COUNT) FROM logs GROUP BY uid; hive> SELECT * FROM logs; a 苹果 5 a 橙子 3 a 苹果 ...
- 15-THREE.JS 方向光
<!DOCTYPE html> <html> <head> <title></title> <script src="htt ...
- es6基础入门变量的解构赋值
let [a, b, c] = [1, 2, 3]; let [foo, [[bar], baz]] = [1, [[2], 3]]; foo bar baz let [ , , third] = [ ...
- ViewPager渲染背景颜色渐变(引导页)--第三方开源--ColorAnimationView
下载地址:https://github.com/TaurusXi/GuideBackgroundColorAnimation 使用方法如下: <FrameLayout xmlns:android ...