NDK-050: 图

50.图

[ConcurrentHashMap](//www.greatytc.com/p/0b452a6e4f4e)

1.Java 多线程的内存模型

HashMap数据存储在主线程内存,
几个线程来修改数据,都会把【主内存】的数据读到线程的【工作内存】中,操作完毕后,再将内容重新 写回到【主内存】。

1.1.HashMap 多线程同时put数据,会出现什么问题?

  • 会出现数据丢失;
    由于子线程相互不可见,数据被其他线程回写时覆盖了。写入白写了。
  • 会出现死循环(扩容时引起的)。
    产生死循环的主要原因是由于 并发操作 和 头插法 导致的。
    因为是头插法,所以 HashMap 的顺序已经发生了改变,但线程 T2 对于发生的一切是不可知的,所以它的指向元素依然没变.
    T1 执行完之后的顺序是 B 到 A,而 T2 的顺序是 A 到 B,这样 A 节点和 B 节点就形成死循环了.

上述问题的 解决方案:
1.使用ConcurrentHashMap:从JDK1.8开始,官方推荐使用 ConcurrentHashMap,
它是一个线程安全的HashMap变体,内部通过分段锁(Segment)机制来保证并发操作的正确性,避免了死循环的问题。
jdk1.8前使用分段的lock;jdk1.8后使用分段的(synchronized + CAS)
CAS:compare and swap 保证线程安全。
2.同步控制:在多线程环境下操作HashMap时,可以通过显式锁定相关代码块来避免死循环。

  1. HashTab(已过时api)-给put加锁 或 Collections.synchronizedMap 锁住put方法。
    都是锁住整个个方法,

如果一个线程在put数据,另外一个线程不允许也不允许get;如果是一个线程get也同理。
把整个方法都锁起来,没有必要。 只需要分段锁住某一个链即可。
操作同一个链表,你改了我不可见,两次刷新就会导致数据丢失;
不是操作同一链表,你改了我不可见,两次刷新没有覆盖的可能,就不会出现数据丢失。
最好的解决方案,只要保证2个线程,不操作同一个链即可。 这就有了分段锁的 ConcurrentHashMap。

1.2 ConcurrentHashMap源码

put的时候,不直接锁住整个方法,只要不操作同一个链,可以同时put数据。---》 分段锁,只锁住单个链。
jdk1.8前使用分段的lock;jdk1.8后使用分段的(synchronized + CAS)
CAS:compare and swap 保证线程安全。

put方法,头结点非空,锁住头结点,
get方法,next和val 都用voilate修饰,保证子线程可见
(数据 被子线程修改但是没有刷到主内存,另外的子线程能读取到修改后的数据)。

2. synchronized 的底层实现原理

synchronized 是怎么实现线程安全的?
synchronized 包起来的代码,会添加2个代码。

synchronized void add(){
// 每个对象头里面有个重要信息 mark work,里面放了gc的分代年龄,hashCode,锁的信息。
// 锁信息moniter:线程id,是否偏向锁,锁的标志 等。
moniterenter(object);
size++;
moniterexit(object);
}
// 有线程1在操作 moniterenter moniter里面的线程信息会被改变,新的线程就等待。
// 线程1执行完后,把工作内存的数据刷新回主内存,然后执行moniterexit,锁的信息回置空,然后把所有在这里等待的线程唤醒。
多个子线程在等待,看谁执行的快。

大多数情况下,只有一个线程,
EventBus 也使用的 ConcurrentHashMap 有可能在eventbus中做多线程,EventBus用在主线程中。
防止在多线程时,使用eventBus通信。

一个线程执行,没必要锁死和唤醒,会好性能。

jdk1.6 再次进行优化,将锁进行分级:

  • 偏向锁:
    第一个线程进来,锁设置为偏向锁;没新的线程进来,不需要唤醒;同一个线程自己重新进来,不需要判断锁id等信息。
    如果只有一个线程,结束时 不要做唤醒这一步,但是锁的状态还是要释放。

  • 轻量级:
    假设有2个线程竞争,第一个线程进去设置的是偏向锁,第二个线程进来 锁住了进不去,他要对锁进行升级,升级为轻量级锁。
    线程二进行自旋(清醒状态,不断地在这里等),假设线程一执行完,发现锁是轻量级锁,就释放锁即可。 线程二可以执行

  • 重量级:
    不断地自旋,肯定会消耗内存,如果迟迟拿不到锁,就必须对锁在进行再升级(重量级锁)线程阻塞等待,
    第一个线程出去的时候,发现是重量级,首先将锁的状态释放,然后通知其他线程竞争锁。

sync 有点像挤地铁,
TODO:lock锁,有点像医院排队,

volatile 关键字:保证内存可见(读写),指令集乱序问题。

发现缓存失效了,重新从主内存读取。

工作内存中,都有一个信号的观察者。
当数据在工作内存修改后,会立即刷到主内存,然后通知每个信号观察者 你的缓存已经失效了,再操作的时候,要从主内存重新读一遍。
每次写的数据,保证另一个线程能看的到。

volatile int size =0;
只加volatile,并不能解决多线程访问数据,数据不可控问题。并不能解决。还是要依赖synchronized锁。
void add(){
size++; // 相当于三行代码,[同步]int temp=get(); temp+=1; [同步]set(temp),中间那行代码容易出问题。
}

《Java的多线程编程艺术》

3.图(Graph)的基础定义

图(Graph)是由顶点的【有穷非空集合】和【顶点之间边的集合】组成,通常表示为:G(V,E),
其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。
图由点和变组成,

注意:线性表中可以没有元素,称为空表。树中可以没有结点,叫做空树。但是在图中不允许没有顶点,可以没有边。

基本术语:
无向边:若顶点V1和V2之间的边没有方向,称这条边为无向边(Edge),用(V1,V2)来表示。
无向图(Undirected graphs):图中任意两个顶点的边都是无向边。
有向边:若从顶点V1到V2的边有方向,称这条边为有向边,也称为弧(Arc),用<V2, V1>来表示,其中V1称为弧尾(Tail),V2称为弧头(Head)。
有向图(Directed graphs):图中任意两个顶点的边都是有向边。

无向完全图:无向图中,任意两个顶点之间都存在边。
有向完全图:有向图中,任意两个顶点之间都存在方向相反的两条弧。
稀疏图;有很少条边或弧的图称为稀疏图 n*log(n),反之称为稠密图。 相对的概念(头发稀疏)完全图肯定是稠密
权(Weight):表示从图中一个顶点到另一个顶点的距离或耗费。
网:带有权重的图.

度:与特定顶点相连接的边数量;
出度、入度:有向图中的概念,出度表示以此顶点为起点的边的数目,入度表示以此顶点为终点的边的数目;
连通图:任意两个顶点都相互连通的图;
生成树:n个顶点,n-1条边 ,的图可以看成树 (生成树)
最小生成树:此生成树的边的权重之和是所有生成树中最小的,找最短路径;

4.图的存储结构

数组存,链表存
顶点 :用数组
边:二维数组(矩阵)

一个图对象,有两个变量:

  • 一个变量存顶点 [V1,V2, V3,V4,V5];
  • 另一个边的二维数组 vertex[5][5]。

  1. 图的深度优先和广度优先遍历

  2. 最小生成树和最短路径

系统学习,书本+视频。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容

  • application [ˌæplɪ'keɪʃ(ə)n]应用程式应用、应用程序 application frame...
    我不白先生阅读 2,013评论 0 3
  • 1 数据2 算法3 线性表4 栈5 队列6 串朴素模式匹配算法 -子串的定位操作:从主串中找到子串KMP模式匹配算...
    oldSix_Zhu阅读 1,499评论 0 4
  • 数据:是描述客观事务的数值、字符以及能输入到计算机中且被处理的各种符号集合。 数据元素:组成数据的基本单位,是数据...
    炎鸿阅读 511评论 0 0
  • 计算机基础 三级存储系统的结构 计算机的三级存储系统是什么?答:计算机系统中存储层次可分为三级:高速缓冲存储器、主...
    臭墨鱼阅读 5,063评论 0 7
  • 大部分内容来自于《大话数据结构》,代码全部使用Swift实现。至于为什么抽风写这个?😊你懂的。 1.线性表 线性表...
    一剑孤城阅读 81,830评论 12 111