synchronized原理Callable接口

synchronized原理

特点 

1.synchronized既是一个悲观锁,又是个乐观锁,自适应的!
   synchronized默认是乐观锁,但是如果发现锁竞争比较激烈,就会变成悲观锁!!
2.synchronized既是轻量级锁,又是一个重量级锁,自适应!
   synchronized默认是轻量级锁,当锁冲突剧烈后,就变成重量级锁!
3.synchronized这里的轻量级锁是基于自旋锁的方式实现的
  synchronized这里的重量级锁是基于挂起等待锁的方式实现的


4.synchronized不是读写锁
5.synchronized是可重入锁
6.synchronized是非公平锁

两个线程针对同一个变量加锁,就会阻塞等待.除了上述基本原理,synchronized还有一些内部的优化机制,存在的目的就是为了让锁更高效,好用.

加锁工作过程——锁升级/锁膨胀

当执行到加锁的代码块儿时,加锁过程就可能经历下面几个升级阶段为了在线程安全和性能做权衡  

无锁
无锁状态,还没开始加锁

偏向锁进行加锁的时候,首先会进入偏向锁状态

偏向锁,并不是真正的加锁,而只是先占个位置,如果有需要就加锁,没需要就不加锁了

相当于"懒汉模式"提到的懒加载一样,非必要,不加锁

synchronized加锁的时候,并不是真正的加锁,而是先进入偏向锁状态,就相当于做一个标记,如果一直没有别的线程来获取这个锁,那么就不会升级,仅仅只做个标记,因为这个变量本来就只有这个线程要使用,过程也没有出现锁竞争,执行完synchronized{}代码块后,再取消掉标记(偏向锁)即可。
但是如果出现了锁竞争,再另一个线程加锁之前,偏向锁会迅速升级为真正的加锁状态!!另一个线程阻塞等待...

偏向锁不是真的加锁, 而只是在锁的对象头中记录一个标记(记录该锁所属的线程). 如果没有其他线
程参与竞争锁, 那么就不会真正执行加锁操作, 从而降低程序开销. 一旦真的涉及到其他的线程竞
争, 再取消偏向锁状态, 进入轻量级锁状态.


轻量级锁
当synchronized发生锁竞争的时候,就会从偏向锁升级为轻量级锁(自旋锁)

此时,synchronized是通过自旋的方式来进行加锁的(就和刚刚伪代码一样的逻辑)

但是,如果很快就释放锁了,自旋是值得的,可以立即获取被释放的锁,反之,迟迟不被释放,那么久迟迟拿不到锁,自旋就不划算了..这时候就需要再次升级了!

重量级锁
一直自旋但是又拿不到锁,synchronized也不会无止境的自旋,此时升级为重量级锁(挂起等待锁)

重量级锁(挂起等待锁)则是基于操作系统原生的API来进行加锁了

linux原生提供了mutex一组API,操作系统北河提供的加锁功能,这个锁是会影响到线程的调度的

此时,如果线程进行了重量级锁的加锁,并且发生了锁竞争,此时线程就会被放入阻塞队列中,暂时不参加CPU的调度了,直到锁被释放了,这个线程才有机会被调度到并有机会获取到锁
锁升级了就不能降级了。

优化过程——锁消除

这是编译器的优化判定,看当前代码是否真的需要加锁,如果这个场景不用加锁,就会自动把加的锁销毁

就像StringBuffer中的关键的方法都是带有synchronized修饰的,就不需要程序员再加锁,加了编译器也会自动销毁!

编译器只会在自己有把握的时候进行锁消除,这个过程在编译过程中触发,而偏向锁是在运行时过程中出现多线程调度的情况,这个线程有可能有人竞争也可能没人竞争,而在编译阶段无法判断锁是否必要,就只能留着。

优化过程——锁粗化

先了解锁的粒度:

synchronized包含的代码越多,粒度就越粗,包含的代码越少,粒度就越细.

通常情况下,粒度细一点比较好,加锁的代码是不能并发执行的,锁的粒度越细,能并发执行的代码就越多,更有利于利用多核CPU资源。粒度越粗能并发的越少,但是如果粒度细的锁被反复进行加锁(涉及反复的锁竞争),可能实际效果不如粒度粗的锁。

eg:领导布置三项简单任务,每次做完你就给领导打电话,打电话相当加锁,每次加锁都涉及到锁竞争,领导那边可能还会有别的事情(别的线程需要加锁,比如开会),领导都烦你了。还不如三项任务都完了再给领导打电话,避免了不必要的所竞争。

有些情况,粒度粗反而更好

这种情况下,两次加锁解锁之间的间隙非常小,反反复复加锁解锁效率低开销大,可以直接加一个大锁,将间隙也包括,效率反而高些,毕竟间隙很小,这块儿代码能不能并发执行影响不大 !

一段逻辑中如果出现多次加锁解锁, 编译器 + JVM 会自动进行锁的粗化.

实际开发过程中 , 使用细粒度锁 , 是期望释放锁的时候其他线程能使用锁 .
但是实际上可能并没有其他线程来抢占这个锁 . 这种情况 JVM 就会自动把锁粗化 , 避免频繁申请释放锁.

Callable接口

是什么 

Callable 是 Java 中的一个接口,位于 java.util.concurrent 包下,用于表示一个可以返回结果并且可能抛出异常的任务,把线程封装了一个 "返回值". 。与 Runnable 接口相比,Callable 接口的 call() 方法支持泛型的返回值,并且允许抛出异常。

类似于Runnable,是用来描述一个任务,区别就是Runnable描述的任务没有返回值,而Callable描述的任务有返回值,Callable通常搭配FutureTask使用,FutureTask用来保存Callable的返回结果,因为Callable往往是在另一个线程中执行的,不知道具体执行完的时间,FutureTask就是负责等待结果出来并保存的。

使用

futureTask就像买餐取餐的小票。而后台厨师就是Thread t,凭小票取餐。

public static void main(String[] args) throws ExecutionException, InterruptedException {
定义任务       Callable<Integer> callable = new Callable<Integer>() {@Overridepublic Integer call() throws Exception {int sum = 0;for (int i = 1; i <= 1000 ; i++) {sum+=i;}return sum;}};
创建线程, 线程的构造方法传入 FutureTask . 此时新线程就会执行 FutureTask 内部的 Callable 的 call 方法, 完成计算. 计算结果就放到了 FutureTask 对象中FutureTask<Integer> futureTask = new FutureTask<>(callable);Thread t = new Thread(futureTask);t.start();
在主线程中调用 futureTask.get() 能够阻塞等待新线程计算完毕. 并获取到 FutureTask 中的结
果. System.out.println(futureTask.get());}
package thread;public class Test {static class Result {public int sum = 0;public Object lock = new Object();}public static void main(String[] args) throws InterruptedException {Result result = new Result();Thread t = new Thread() {@Overridepublic void run() {int sum = 0;for (int i = 1; i <= 1000; i++) {sum += i;}synchronized (result.lock) {result.sum = sum;result.lock.notify();}}};t.start();synchronized (result.lock) {while (result.sum == 0) {result.lock.wait();}System.out.println(result.sum);}
//        t.join();
//        System.out.println(result.sum);}}

小结: 线程的创建方式
1.继承 Thread, 重写 run(创建单独的类,也可以匿名内部类)2.实现 Runnable,重写 run(创建单独的类, 也可以匿名内部类)3.实现 Callable, 重写 call (创建单独的类,也可以匿名内部类)
4.使用 lambda 表达式
5.ThreadFactory 线程工厂
6.线程池 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/693393.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

字符串算法(算法竞赛)--最小表示法与最详细的字符串哈希

1、B站视频链接&#xff1a;F01 最小表示法_哔哩哔哩_bilibili 题目链接&#xff1a;【模板】最小表示法 - 洛谷 #include <bits/stdc.h> using namespace std; const int N7e5; int n; int s[N];int get_min(){for(int i1;i<n;i)s[ni]s[i];//字符串复制一倍int i1,j…

车载软件架构Adaptive AUTOSAR —— 身份和访问管理和加密技术

车载软件架构Adaptive AUTOSAR —— 身份和访问管理和加密技术 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师(Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 本就是小人物,输了就是输了,不要在意别人怎么看自己。…

辽宁博学优晨教育科技有限公司视频剪辑培训靠谱吗?

在数字媒体日益繁荣的今天&#xff0c;视频剪辑已成为一项炙手可热的技能。不少培训机构纷纷涉足这一领域&#xff0c;辽宁博学优晨教育科技有限公司便是其中之一。然而&#xff0c;面对众多的选择&#xff0c;很多人不禁要问&#xff1a;辽宁博学优晨教育科技有限公司的视频剪…

【深度学习每日小知识】交并集 (IoU)

交并集 (IOU) 是一种性能指标&#xff0c;用于评估注释、分割和对象检测算法的准确性。它量化数据集中的预测边界框或分段区域与地面实况边界框或注释区域之间的重叠。 IOU 提供了预测对象与实际对象注释的对齐程度的衡量标准&#xff0c;从而可以评估模型准确性并微调算法以改…

中科大计网学习记录笔记(十四):多路复用与解复用 | 无连接传输:UDP

前言&#xff1a; 学习视频&#xff1a;中科大郑烇、杨坚全套《计算机网络&#xff08;自顶向下方法 第7版&#xff0c;James F.Kurose&#xff0c;Keith W.Ross&#xff09;》课程 该视频是B站非常著名的计网学习视频&#xff0c;但相信很多朋友和我一样在听完前面的部分发现信…

人形机器人专题:传感器,人形机器人实现“具身感知”的关键

今天分享的是人形机器人系列深度研究报告&#xff1a;《人形机器人专题&#xff1a;传感器&#xff0c;人形机器人实现“具身感知”的关键》。 &#xff08;报告出品方&#xff1a;浙商证券股份有限公司&#xff09; 报告共计&#xff1a;44页 来源&#xff1a;人工智能学派…

Redis篇----第十篇

系列文章目录 文章目录 系列文章目录前言一、Redis 集群如何选择数据库?二、怎么测试 Redis 的连通性?三、怎么理解 Redis 事务?四、Redis 事务相关的命令有哪几个?五、Redis key 的过期时间和永久有效分别怎么设置?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易…

备考2025年AMC8数学竞赛:2000-2024年AMC8真题练一练

对于想了解或者加AMC8美国数学竞赛的孩子来说&#xff0c;熟悉AMC8的历年考试真题&#xff0c;既可以了解考试的内容、形式、难度&#xff0c;还可以看看自己的掌握程度&#xff0c;发现自己的短板查漏补缺&#xff0c;毕竟&#xff0c;这个比赛考察的知识点相对固定&#xff0…

14. rk3588自带的RKNNLite检测yolo模型(python)

首先将文件夹~/rknpu2/runtime/RK3588/Linux/librknn_api/aarch64/下的文件librknnrt.so复制到文件夹/usr/lib/下&#xff08;该文件夹下原有的文件librknnrt.so是用来测试resnet50模型的&#xff0c;所以要替换成yolo模型的librknnrt.so&#xff09;&#xff0c;如下图所示&am…

【Python爬虫】requests库get和post方法使用

requests库是一个常用于http请求的模块&#xff0c;性质是和urllib&#xff0c;urllib2是一样的&#xff0c;作用就是向指定目标网站的后台服务器发起请求&#xff0c;并接收服务器返回的响应内容。 1. 安装requests库 使用pip install requests安装 如果再使用pip安装python…

kali linux出现添加源无法更新的问题:更新时显示签名无效和没有数字签名

kali linux更新源时显示签名无效和没有数字签名 一、出现显示签名无效和没有数字签名二、 解决办法三、几种开源镜像站 一、出现显示签名无效和没有数字签名 原因&#xff1a;因为没有下载签名&#xff0c;所以显示签名无效和没有数字签名 二、 解决办法 wget archive.kali.o…

OpenCV边缘检测与视频读写

原理 OpenCV中的边缘检测原理主要基于图像梯度的计算&#xff0c;包括一阶梯度和二阶梯度。 一阶梯度&#xff1a;它反映了图像亮度变化的速度。Sobel算法就是一种以一阶梯度为基础的边缘检测算法。它通过计算图像在水平和垂直方向上的梯度来检测边缘。这种方法简单有效&…

命令行窗口文本复制到 Word 格式保持不变

命令行窗口文本复制到 Word 格式保持不变 References 标题栏右键 -> 编辑 -> 标记 / 全选 标题栏右键 -> 编辑 -> 复制 粘贴到 Notepad 中&#xff0c;语言栏设置对应语言&#xff0c;格式可以保持不变 复制文本粘贴到 Excel 中 选中 Excel 中文本复制&#xf…

基于qt的图书管理系统----01数据库设计

参考b站&#xff1a;视频连接 目录 1、数据库设计2、数据库增删改查2.1 book表操作2.2 user表操作2.3 record表的操作&#xff08;重点&#xff09; 3、数据表导出 1、数据库设计 使用sqlite3&#xff0c;新建一个book的表&#xff0c;并且都让主键自增 NmaeValuebookid书本…

GIN框架介绍以及使用

Gin是一个用Go语言编写的web框架。它是一个类似于martini但拥有更好性能的API框架, 由于使用了httprouter&#xff0c;速度提高了近40倍。 如果你是性能和高效的追求者, 你会爱上Gin&#xff0c;而且现在大多数企业都在使用Gin框架&#xff0c;反正学一学总没有错。 1、 GIn框…

赞:java使用easy-excel导入数据的通用模板思路

我们在项目中都会有导入导出的功能&#xff0c;这篇文章主要是讲导出的&#xff0c;导入我会在另外一篇博客文章中讲解。 现在我们开始。 首先&#xff1a;需要在项目中的pom.xml中导入easy-excel的依赖 <!--使用esay-excel进行导入导出 --> <dependency> &…

实习日志26 捷通打印机交接

概要 捷通打印机的研究和使用需要下载一些软件 打印机驱动下载说明 驱动&#xff1a;选择DL-721Z 端口选择&#xff1a;USB002 智能助手&#xff1a;&#xff08;连接&#xff0c;设置打印机&#xff09; 打印机显示 rfid未校准 时可以在这里点RFID标签校验 LabelEditor编译…

unity学习(31)——跳转到角色选择界面(打勾?手滑挂错脚本)

There are 2 audio listeners in the scene. Please ensure there is always exactly one audio listener in the scene. 是因为后来创建了一个camera&#xff0c;因为camera中自带一个组件Audio Listener。所以有两个camera就有两个audio listener导致报错。 一个简单的解决…

超声波清洗机大测评!希亦、洁盟、德国ODI、苏泊尔哪款性价比高?

眼镜逐渐已经成为现在大部分都离不开的一个视线辅助&#xff0c;但是很多朋友对于眼镜的清洗从开始佩戴眼镜时&#xff0c;就没有重视起来。其实清洗眼镜的方法有很多种&#xff0c;手动清洗跟超声波清洗机&#xff0c;后者的清洗相对来说会更加方便快捷一点&#xff0c;且清洗…

计算机网络——15套接字编程

套接字编程 Socket编程 Socket编程&#xff1a;应用进程使用传输层提供的服务才能够交换报文&#xff0c;实现应用协议&#xff0c;实现应用 TCP/IP&#xff1a;应用进程使用Socket API访问传输服务 地点&#xff1a;界面上的SAP 方式&#xff1a;Socket API 目标&#xff1…