java并发 递归 性能_Java高并发syncronized深入理解

1.Synchronized的作用:

能够保证在同一时刻最多只有一个线程执行该段代码,以达到保证并发安全的效果。

2.地位:

1)Synchronized是java的关键字,并java的怨言原生支持;

2)最基础的互斥同步手段;

3)并发编程中的元老级角色,是并发编程的必学内容。

3.不使用并发手段会有什么后果?

(1)两个线程同时a++,最后结果会比预想的少

原因:count++实际上是有3个操作完成:

1)读取count;

2)将count加一;

3)将count的值写入到内存中。

4.Synchronized的两个用法:

(1)对象锁:包括方法锁(默认锁对象为this当前实例对象)和同步代码块锁(自己指定锁对象);

(2)类锁:指synchronized修饰静态的方法或指定锁为Class对象。

5.synchronized类锁

概念:Java类可能有很多个对象,但只有一个Class对象,类锁时Class对象的锁(类锁只能在同一时刻被一个对象拥有)

形式:

1)synchronized加在static方法上;

2)synchronized(*.class)代码块。

6.多线程访问同步方法的7种情况:

1)两个线程同时访问一个对象的同步方法;

解释:对象所。会相互等待,只能有一个线程持有锁。

2) 两个线程访问的是两个对象的同步方法;

解释:对象锁。不同的对象实例,拥有不同的对象锁,互不影响并发执行。

3) 两个线程访问的是synchronized的静态方法;

解释:类锁。

4) 同时访问同步方法与非同步方法;

解释:synchronized关键字只作用于当前方法,不会影响其他未加关键字的方法的并发行为。因此非同步方法不受到影响,还是会并发执行。

5) 访问同一个对象的不同的普通同步方法;

解释:对象锁。

synchronized关键字虽然没有指定所要的那个锁对象,但是本质上是指定了this这个对象作为它的锁。所以对于同一个实例来讲,两个方法拿到的是同一把锁,因此会出现串行的情况。

6) 同时访问静态synchronized和非静态的synchronized方法;

解释:前者为类锁,锁为Class类;后者为对象锁,锁为this对象。因此两者的锁不同,会并行执行。

7) 方法抛异常后,会释放锁。

特殊:Lock类加锁时,如果出现异常,不显式手动释放锁的话,Lock是不会释放的。

而synchronized不同,一旦出现异常,会自动释放锁。

也就是说当第二个线程等待一个被synchronized修饰的方法时,若第一个线程出现异常退出,这把锁会立刻释放并且被第二个线程所获取到。JVM会自动把锁释放。

8)扩展:线程进入到一个被synchronized修饰的方法,而在这个方法里面调用了另外一个没有被synchronized修饰的方法,这个时候还是线程安全的吗?

答案:不是的。出了本方法后,由于另外的方法没有被synchronized修饰,所以说这个方法可以被多个线程同时访问的。

7.synchronized核心思想总结:

1)一把锁同时只能被一个线程获取,没有拿到锁的线程只能等待(对应1,5);

2)每个实例对应自己的一把锁,不同实例对应不同的锁,相互不影响,可以并行。例外:如果锁是*.class以及synchronized修饰的是static方法时,即类锁时,所有对象共用一把锁(对应2,3,4,6)

3)无论是正常执行还是抛出异常,都会释放锁(对应7)

8.syscronized性质(可重入,不可中断)

1)可重入:一个线程拿到了锁,这个线程可以再次使用该锁对其他方法,说明该锁是可以重入的;

2)不可重入:一个线程拿到锁了,如果需要再次使用该锁,必须先释放该锁才能再次获取。

可重入锁的好处:

1)避免死锁 2)提升封装性

粒度:

可重入的特性是线程级别的,不是调用级别的(pthread线程)。

问题:为什么synchronized具有可重入性?

答:指的是同一线程的外层函数获得锁之后,内层函数可以直接再次获取该锁(可避免死锁,锁方法1在内部访问锁方法2,用的是同一把锁)。

什么样的可重入?

1)同一个方法是可重入的;

2)可重入不要求是同一个方法;

3)可重入不要求是同一个类中的。

synchronized的性质:不可中断性质

1)线程A拿到锁,不释放的话,别人永远拿不到锁,永远等待;

2)Lock锁会有一些比较灵活的功能,按时间等。

加锁和释放锁的原理:

现象:

每个类的实例对应着一把锁,每个syncronized方法首先必须获得调用该方法实例的锁,才能执行;否则,线程只能被阻塞。方法一旦执行,便独占了该把锁。直到该方法执行结束返回或者抛出异常,才将该锁释放。锁释放之后,其他阻塞锁才能竞争获取该把锁。

当一个对象中有synchronized修饰的方法或者代码块的时候,要想执行这段代码,就必须先获得这个对象锁,如果此对象的对象锁已经被其他调用者所占用,就必须等待它被释放。所有的Java对象都含有一个互斥锁,这个锁由JVM自动去获取和释放,我们只需要指定这个对象就行了,至于锁的释放和获取不 需要我们操心。

获取和释放锁的时机:内置锁(监视器锁)

线程在进入同步代码块之前,会自动获取该锁,并且退出代码块时会自动释放该锁。无论是正常退出或者抛出异常退出,都会释放锁。

然而获取锁的唯一途径:进入这个锁保护的同步代码块或者同步方法中。

Jvm字节码:

1)将Java文件编程为.class文件:javac xxx.java;

2)通过反编译查看字节码,javap -verbose xxx.class;

3)synchronized如何实现的,有个加锁monitorenter和解锁monitorexit读到该指令,会让monitor计数器+1或-1。

注意点:线程既可以在方法完成之后退出,也可以在抛出异常后退出,因此monitorexit数量多于monitorenter。

可重入原理:(加锁次数计数器)

1)jvm负责跟踪对象被加锁的次数。

2)线程第一次给对象加锁的时候,计数变为1.每当这个相同线程在此对象上再次获得锁时,计数会递增。

3)每当任务离开时,计数递减,当计数为0时,锁被完全释放。

(1)可重入:如果线程已拿到锁之后,还想再次进入由这把锁所控制的方法中,而无需提前释放,可以直接进入。

(2)可重入:指的是同一线程的外层函数获得锁之后,内层函数可以直接再次获取该锁。也叫做递归锁。Java中两大递归锁:Synchronized和ReentrantLock。

可见性原理:java内存模型

线程A向线程B发送数据的两个步骤:

1)线程A修改了本地内存A,并将其存储到主内存中。

2)线程B再从主内存中读取出来。

这个过程是由JMM(Java Memory Model)控制的。JMM通过控制主内存与每个线程的本地内存的交互来为Java程序员提供内存可见性的保证。

synchronized是如何做到内存可见性的实现?

一旦一个代码块或者方法被synchronized修饰之后,那么它在执行完毕之后被锁住的对象所做的任何修改都要在释放锁之前从线程内存写回到主内存 中。所以下一个线程从主内存中读取到的数据一定是最新的。就是通过这样的原理,synchronized关键字保证了每一次执行都是可靠的,保证了可见性。

9.Synchronized的缺陷

1)效率低:

锁的释放情况少;试图获得锁时不能设定超时;不能中断一个正在试图获得锁的线程。

2)不够灵活(读写锁更灵活:读操作的时候不会加锁,写操作的时候才会加锁):

加锁和释放的时机单一;每个锁仅有单一的条件(某个对象),可能是不够的。

3)无法知道是否成功获取到锁。

但是,lock有一些不一样的特性:

Lock可以尝试成功了做一些逻辑判断,如果没有成功做另外一些逻辑判断.

Lock类:

lock.lock();lock.unlock();

通过这两个方法,可以手动加锁和解锁。

lock.tryLock();lock.tryLock(10, TimeUnit.MINUTES);

可以判断是否加锁,返回类型为boolean

补充重点:

1.synchronized的使用注意点:

锁对象不能为空:锁的信息保存在对象头里面作用域不宜过大:synchronized关键字包裹的范围。

不需要串行工作的情况下,用并行的方式可以提高运行的效率避免死锁。

2.如何选择Lock和synchronized关键字?

1)如果可以的情况下,两者都不要选择,而是使用java.util.concurrent包中的各种各样的类,例如:CountDownLatch等。使用这些类,不需要自己做同步工作,更方便,也更不容易出错。

2)如果synchronized关键字在程序中适用,就优先实用这个关键字。因为这样可以减少需要编写的代码,就减少了出错的几率。

3)如果特别需要Lock这样结构独有的特性的时候,才使用Lock。

以上三点主要是基于减少代码出错为出发点。

10.思考题

1)多个线程等待同一个synchronized锁的时候,JVM如何选择下一个获取锁的是哪个线程?

锁调度机制。对于synchronized内置锁,不同版本的JVM处理方式不同,blocked和running都有几率。

2)synchronized使得同时只有一个线程可以执行,性能较差,有什么办法可以提升性能?

(1)优化使用范围,让加锁区在业务允许的情况下足够小。

(2)用其他类型的锁,例如读写锁,这样在读的时候就不止一个线程可以同时进入代码。

3)我想更灵活地控制锁的获取和释放(现在释放锁的时机都被规定死了),怎么办?

自己实现一个Lock

4)什么是锁的升级、降级?什么是JVM里的偏斜锁、轻量级锁、重量级锁?

在之前的JVM版本中,synchronized性能不是特别的好,而经过不断的迭代,synchronized性能已经得到了显著的提高,这里面运用的技术就是偏斜锁、轻量级锁、重量级锁。JVM会根据synchronized关键字使用到的次数或者其他的种种指标对锁进行有效的优化使得性能得到大幅上涨,这里面还涉及到了对象头里面的字段。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值