Java基础day11笔记:多线程同步函数|synchronized的几种锁|死锁

    11-多线程(多线程-同步函数)

        银行类:

        储户类:

        主函数中开两个线程:

        运行结果:

        但是多运行几次,发现顺序不太对:

        如何找问题?

        1,明确哪些代码是多线程运行代码。

        2,明确共享数据。

        3,明确多线程运行代码中哪些语句是操作共享数据的。

        我们就来一条一条找:

        1,哪些代码是多线程运行代码:

        2,共享数据。

        3,多线程运行代码中哪些语句是操作共享数据的:

        run方法中只有一句应该不是问题所在,add方法中有两句,我们来分析一下:

        第一个线程进入add,给sum加了n,还没来的及打印,下一个就占用了cpu,也进入了add,做给sum加n的动作,它加完打印完之后,刚刚那个没来得及打印的线程才获得了cpu的执行权,继续打印,这个时候,就会导致打印的顺序不对。

        为了验证,我们sleep一下:

        编译运行:

        天啦噜,问题好严重!

        我们要解决问题!

        编译运行:

        问题解决啦。

        那我们可以把这部分锁着吗?

        也不是不可以,但又一个问题,就是如果李四进来了,得等到他把300块钱全存完,张三才能进来。

        所以,哪些代码该同步,哪些代码不该同步,一定要搞清楚。

        怎么搞清楚呢?就刚刚那三个步骤。

         如何找问题?

        1,明确哪些代码是多线程运行代码。

        2,明确共享数据。

        3,明确多线程运行代码中哪些语句是操作共享数据的。

        接下来要讲新知识点啦。

        我们思考一下:

        同步代码块是用来封装代码的,函数也是用来封装代码的,那它们有什么不同呢?

        同步代码块相对比函数,是拥有了同步性,那我们也让函数具有同步性,这个点子怎么样?

        其实超级简单,把synchronized关键作为修饰符放在函数上就OK啦:

        总结一下:

        同步有两种表现形式,第一个是同步代码块,第二个是同步函数。

    12-多线程(多线程-同步函数的锁是this)

        我们现在把之前卖票的程序也改成同步函数玩一下~

        编译运行:

        我们发现,一直是0线程在做这件事情,1、2、3线程根本没启动。

        我们分析一下,0进来了,1、2、3被锁外面了,而0一进来就一直循环直到结束,1、2、3根本没有机会:

        所以这么做不可以,因为没有搞清楚哪些需要同步,哪些不需要。

        那该怎么写呢?单独写一个函数:

        这个问题就解决啦。

        但是另一个问题来了,我们这里已经没有object对象了,那同步函数用的是哪个锁?

        show方法是不是需要被对象调用的呀?那同步函数能够用到的锁,就是调用它的对象:this。

        因为函数需要被对象调用,那么函数都有一个所属对象引用,就是this。

        所以同步函数使用的锁是this。

        我们现在来验证一下:

        使用两个线程来卖票。一个线程在同步代码块中,一个线程在同步函数中,都在执行卖票动作。

        如果要是同步的话,就不会出现错误。

        稍微修改一下代码:

        同步代码块:

        同步函数:

        主函数总开启两个线程:

        编译运行:

        0线程也有,1线程也有,可是为什么全都是show?code没打印。

        分析一下:现在有三个线程:主线程,0线程,1线程。

        主线程启动后,创建了两个线程对象,然后开启了0线程,开启完之后,0线程会立刻执行吗?不一定,它先是处于临时状态,有了资格但是还没有执行权,因为这个时候是主线程持有执行权。主线程有可能瞬间把这几句话执行完:

        瞬间几句话执行完后,flag值为false。

        主线程执行完t2.start()之后,就结束了。

        现在就剩两个线程:0线程和1线程,它们开始运行了。

        因为flag值为false,所以0线程和1线程都去show中执行了。

        那该怎么解决呢?

        想让主线程执行完t1.start()之后先停一下,让0线程运行一会儿:

        注意,在主线程睡眠的这10ms内,能运行的线程只有0线程,这个时候他就去执行同步代码块了。

        过了10ms,主线程醒了。醒完以后,它继续往下执行,将flag置为假,开启了1线程,1线程就去执行同步函数show了。

        此时0线程和1线程同时运行。

        编译运行:

        搞定!

        但是这里出现错票了:

        因为票数只能到1,出现卖0号票就错了。

        所以不安全。

        可是明明加了同步,怎么就能不安全呢?

        加了同步还没解决,肯定是两个前提中至少有一个没满足。

        前提:

        1,必须是两个及两个以上的线程。满足了。

        2,用的是同一个锁。不是。0线程用的obj锁,1线程用的this锁。

        我们将同步代码块也改成this锁试一试: 

        编译运行:

        安全啦!

        通过这个小程序,我们也侧面验证了同步函数使用的锁是this,一箭双雕嘻嘻~

    13-多线程(多线程-静态同步函数的锁是Class对象)

        我们将show用static修饰:

        tick也用static修饰:

        编译运行:

        我们发现,又出现0号票了,怎么会酱紫!

        因此,静态的同步函数,用的锁肯定不是this了(因为静态方法中也不可以定义this),那么它用的锁是什么呢?

        静态进内存时,内存中没有本类对象,到那时一定有该类对应的字节码文件对象:类名.class,该对象的类型是Class。

        所以将同步代码块的锁修改成Ticket.class试一下:

        编译运行:

        安全啦!

        因此,静态的同步方法,使用的锁是该方法所在类的字节码文件对象:类名.class。

    14-多线程(多线程-单例设计模式-懒汉式)

        讲完了这些,我们回过头看一下之前讲过的单例设计模式——懒汉式。因为这个小知识点只有我们学完同步之后才能讲~   

        我们回顾一下单例设计模式:

        饿汉式:

        懒汉式:

        这里有一个问题,如果多个线程并发访问这个getInstance,是不是有多条语句在操作共享数据s?(一条在判断,一条在赋值。)

        加上synchronized就搞定了:

        但是还有个问题,如果有很多个线程都要访问getInstance,是不是每个线程都要访问这个锁?所以懒汉式加了同步会比较低效。

        怎么办呢?

        这个时候我们可以这样干:

        但是这样写和那样写不是没啥区别嘛,那再加一句:

        我们分析一下:

        A一进来,满足第一次s==null判断,拿到锁就进来了,进来之后A挂这里了:

        B一进来,也满足第一次s==null判断,但是没拿到锁。

        这个时候A继续执行s=new Single();并且在执行完之后就出去啦。

        这时候B拿到了锁,也进来了。进行第二次s==null的判断,显然不满足。所以return s。

        这时C进来了,进行第一次s==null的判断,不满足。而且C以后进来的线程,它们都不满足第一次s==null的判断,所以都不用再判断这个锁。

        这样做,减少了判断锁的次数。

        所以用双重判断,减少了判断锁的次数,稍微提高了懒汉式的效率。

        但是不管怎样,饿汉式只有一句话就可以解决的问题,懒汉式都要用好几句。所以开发中还是写饿汉式好一些。

        之所以讲这么详细,是因为在面试中经常会考到懒汉式。

        比如饿汉式和懒汉式有什么不同?懒汉式的特点在于实例的延迟加载。

        懒汉式的延迟加载有没有问题?有, 如果多线程访问时会出现安全问题。 

        怎么解决?用同步来解决。用同步代码块或者同步函数都可以,但是稍微有点低效。用双重判断可以稍微解决一下效率问题。

        加同步的时候使用的锁是哪一个?该类所处的字节码对象。

        所以,就这一个小问题可以考好多地方呢。

        这个代码要会写哦:

        一般有可能会要求:请写一个延迟加载的单例设计模式示例。就写这个~

    15-多线程(多线程-死锁)

        刚刚讲的this锁和字节码对象锁结论记住就行啦,代码有点麻烦,了解即可。但是单例设计模式的代码一定要会哦。        

        回到我们的进度中来。

        同步还有一个弊端:死锁。这是同步出现之后会产生的一个现象。

        何为死锁呢?

        你持有一个锁,我也持有一个锁,我不放我的锁要到你那里面去运行,而你不放你的锁要到我这里面去运行。谁都不放,就导致了死锁。

        死锁一产生,程序就挂那儿不动了。

        通常死锁出现的原因是:同步中嵌套出现,而锁却不同。

        我们稍微修改一下代码,让它出现这种情况:

        编译运行,卡这里不动了:

         我们分析一下: 

        这个时候就锁住了。

        注意这样写不是教你写死锁哦,是要你一定要避免死锁~

        再来一个稍微简单的死锁例子:

        Test类实现Runnable接口:

        为了方便起见,单独写了一个类装俩锁(锁是对象哦):

        run方法中:

        主函数中:

        编译运行:

        锁住了。

        分析原因:

        当然多运行几次偶尔也会出现和谐的情况。(但是这只是侥幸!)

        面试的时候,有一道考题叫:请给我写一个死锁程序。这个考的就是对死锁的理解。能写出来,就说明对死锁理解的差不多了,避免死锁也不是问题了。

        终于写完啦,吃午餐去辣!想吃面面~

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

推荐阅读更多精彩内容