array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 synchronized 只看一篇就够了 - 爱码网

这个关键字涉及的知识点比较多。这里准备从她的作用。她的使用。她的原理。以及她的兄弟姐妹四个方面来讲。
首先她的作用。
1.多线程同步里头作为 锁 能锁类。能索对象。能锁代码块
2.在synchronized包含的代码块开头跟结尾的部分加入了共享变量的数据同步,我个人认为第二条才是为啥这个关键字起名的原因。为了同步嘛。至于如何同步在使用过程中一一解析

先看常用锁的部分。

  1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
  2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
  3. 修饰一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;

锁对象跟类 有点太抽象。换成通俗的说法。对象就是每次你new 出来的那个Object。类其实也是一个Object. 比如Integer.class。但是这类class 是单例的。就是有且只有一个。下面用实际代码来加深印象。

第一种 代码块
synchronized(XXX){
}

这里XXX 基本可以是具体的对象。 Object a=new Object(); synchronized(a){} 这种对象一旦被锁上。这个对象其他的被synchronized包含的不管是方法(要抛去static synchronized 锁的是 Object.class对象是另一个对象)还是代码块 是都进不去的。只有等待{}完成。但是如果是Object b=new Object() 是另一个对象。b的所有方法还是可以随便访问的。

如果XXX是 this这个关键字 锁的是具体的对象。还是上面那个规则。同对象就要等代码块执行完。不同对象无所谓。

如果XXX是 BBB.class 。比如
synchronized 只看一篇就够了
那不管是FlyweightFactory a=new FlyweightFactory(); FlyweightFactory b=new FlyweightFactory();
那不管是a.getFlyweightMapSize 还是b.getFlyweightMapSize 都会被锁。这里锁的是一个独一无二的Class对象
这个Class对象跟 this是不同的对象。所以下面的代码块是依然可以进入的。
synchronized 只看一篇就够了
最后看看加在静态方法上会是什么结果。锁的是类还是对象。答案是类。也就是等同于synchonized(class)。
synchronized 只看一篇就够了
这两个方法执行的时候 一旦有一个进入了代码块,另一个就要等代码块执行完。注意是代码块。就是{}。ok到这里使用就说完了。下面开始讲原理 synchonized究竟干了啥

这里我不想跟其他文章一样开始说什么monitor对象 java对象头 这些都是具体细节。我就想讲一个基本的实现逻辑。 这个synchonized东西是跟我们现实场景是很像的.就是去银行办理业务。你进门就要拿一个号。前面要有人你就要排队。实际上不管是她的兄弟Lock还是后面其他各种升级版本 AQS 都是这个逻辑,就是拿一个凭证进队列。没到你,你就只能等。当然为了更有效率。就有了各种锁。早期synchonized还是很慢的。但是随着jdk的升级。底层对synchonized这个做了很多优化。具体不讲了。总结一句话就是有了各种场景的判断,在不同的场景下让效率更高。因为都是底层的活这里就一一说明了。最后要讲一个synchonized 对成员变量可见性的影响 。就是 synchonized代码块里头如果用到了 成员变量或者说是共享变量。那进入的时候会强制刷新一次从共享内存到工作内存的同步。 同理,在退出的时候,会完成一次工作内存到共享内存的同步。这个到底意义何在。

一定要记住是在代码块全部完成的时候,才会同步到共享内存。比如有给boolean成员变量 一个方法是修改。一个方法是读。假如在方法执行到修改的方法执行到一半boolean 从true变成false,但是这个false是工作内存的变量值。 但是方法的因为底层调度切换到了读的方法。对不起这个读的方法因为读的还是主内存的拷贝还是ture。内存可见性问题来了。要解决这个问题咋办呢。第一种是给读写的方法都加上synchonized。有啥作用呢。就是延迟读。大家脑补一下。假如还是刚才执行到一半。但是方法还没结束。线程确实也切换了读。但是发现因为加了锁进不去方法。只能等待刚才的方法完全执行完。而方法执行完的时候工作内存已经完成了同步了。主内存的值已经变成了false。再切换到读方法的时候。因为锁解除。方法能进。第二个变量要完成一次主内存到工作内存同步。已经是false。刚才的不同步的问题就解决了。 第二种就是涉及到了volatile这个关键字。后面再讲。

最后要说说synchonized 的一些缺点。很多场景实现不了的。第一个就是我可以拿锁,但是拿不到我不想等的情况 。第二种是两个方法。对一个共享变量。这个共享变量没有别的地方独写。一读一写的情况。读的时候可以随便进。写的时候要看有没有锁。有写锁或者读锁都不能进。这两种情况synchonized 都没法实现。第三种情况 保证排队的顺序。synchonized的队列默认是非公平的。也就是排队10人。先来的未必先执行,看运气。 synchonized 会导致死锁。下面给一个最简单的死锁里头
Object a ,b

synchonized(a){
synchonized(b){
}
}

synchonized(b){
synchonized(a){
}
}

很简单。就是多个对象嵌套使用的时候。同时进a。同时进b。 a拿不到b。 b也拿不到a。 所以在有嵌套的时候要小心。

相关文章: