当前位置: 首页 > news >正文

嘉纪商正网站建设公司公司网站建设接单

嘉纪商正网站建设公司,公司网站建设接单,品牌网站建设 杭州,东莞做一个企业网站前言#xff1a; #x1f308;上期博客#xff1a;【后端开发】JavaEE初阶—线程安全问题与加锁原理#xff08;超详解#xff09;-CSDN博客 #x1f525;感兴趣的小伙伴看一看小编主页#xff1a;GGBondlctrl-CSDN博客 ⭐️小编会在后端开发的学习中不断更新~~~ #… 前言 上期博客【后端开发】JavaEE初阶—线程安全问题与加锁原理超详解-CSDN博客 感兴趣的小伙伴看一看小编主页GGBondlctrl-CSDN博客 ⭐️小编会在后端开发的学习中不断更新~~~ 非常感谢你的支持 目录 ️1.引言 ️2.可重入锁 2.1概念 2.2原理理解 ️3.死锁 3.1产生死锁的情况 1.一个线程一把锁 2.两个线程两把锁 3.N个线程M把锁 3.2解决死锁的方法 ️4.内存可见性 4.1内存可见性实例 4.2内存可见性原理 4.3内存可见性解决 1.进行线程休眠 2.添加volatile关键词  ️5.总结 ️1.引言 OK啊小伙伴们本小编又带来了一个重磅知识我们上期讲解了关于线程安全问题引出了加锁这个概念但是加锁会产生一个严重的问题就是当我们运用不当时进行加锁会导致死锁的发生那怎样才会导致死锁呢以及如何避免呢这就是小编本期的重要内容 发车发车gogogog~~~ 且听小编讲解包你学会  ️2.可重入锁 2.1概念 什么是可重入锁呢让我们看看以下代码 public static void main(String[] args) {Object locknew Object();//可重入锁实例Thread t1new Thread(()-{synchronized (lock){synchronized (lock){System.out.println(Hello thread);}}});t1.start(); } 对于如何进行加锁操作小编上期有讲不清楚的小伙伴可以自己去看看哦~~~ 开始认知这里由于lock已经被加过一次锁了那么接下来再加一次锁不会发生线程阻塞吗第一次加又没有进行释放  注意上面这种理解完全是错误的这里就是由于使用同一个线程此时的锁对象就能够知道第二次加锁的线程是持有锁的线程那么在第二次加锁时就直接通过就不会发生“阻塞”现象 这种特性叫可重入性这个锁就叫做可重入锁~~~ 2.2原理理解 在Java中实现可重入锁是非常简单的因为synchrinized自带这个特性那么这个特性的内部原理是啥呢且看如下图所示 注意对于重入锁来说最主要两部分第一个就是对于加锁的线程是否为同一个线程第二就是对于加锁过程的计数器的次数理解 以上都是在java中synchronized封装实现的那么在C中就没有重入锁的概念此时当存在复杂的调用关系的时候就会存在卡死的情况就是“死锁”接下来就注重“死锁”的理解 ️3.死锁 在之前讲解过加锁可以解决线程安全问题但是操作不当会产生“死锁”的情况 3.1产生死锁的情况 1.一个线程一把锁 即在上述讲解过程中的可重入所情况但是如果没有可重入这个性质那么连续对一个线程加锁两次那么就会产生死锁 2.两个线程两把锁 即有两个线程当线程1加上锁A线程2加上锁B那么然后在两个锁不进行释放的前提下双方都想拿到对方的锁此时就会发生死锁的情况 这里有代码进行演示 Object Anew Object();//对象AObject Bnew Object();//对象B//创建线程t1拿到锁Thread t1new Thread(()-{synchronized (A) {System.out.println(线程t1拿到了锁A);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException();}//线程进入休眠保证另一个线程也能够拿到锁//尝试拿到对方的锁,此时锁A没有释放synchronized (B) {System.out.println(线程t1拿到了两把锁);}}}); 此时小编设置了两个对象即两个锁对象那么我们就进行线1的加锁此时当我们拿到锁A后在不解开锁的情况下进行另外一把锁B的获取 Thread t2new Thread(()-{synchronized (B) {System.out.println(线程t2拿到了锁B);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException();}//线程进入休眠保证另一个线程也能够拿到锁//尝试拿到对方的锁没有释放自己的锁synchronized (A) {System.out.println(线程t2拿到了两把锁);}}}); 此时我们就行第二个线程的实现和上述线程1一样当拿到自己的锁之后在不解开锁的情况下进行锁A的获取然后两个线程启动之后的结果就是 此时可以发现线程各自拿到自己的锁之后就直接“卡住”了这就发生了线程安全问题 当我们打开jconsole后可以看看我们的线程情况 这是我们的两个对应的线程名字此时两个线程的执行状态就如下图所示 注意此时可以看到线程1处于BLOCKED状态并且在等锁B那么锁B的拥有者是线程2同理线程2在等锁A而锁A的拥有者就是线程1 可以发现此时两个锁都在等对方释放锁此时就产生了死锁 3.N个线程M把锁 此时这种情况就是要考虑到“哲学家就餐问题了”什么是哲学家就餐问题呢 解释此时有5个哲学家要吃面但是筷子只有5根这无根筷子在每个哲学家之间此时就是五个哲学家就是五个线程筷子就是锁当每个哲学家拿到筷子后旁边的两哲学家是吃不到的就处于阻塞的状态一般情况下哲学家啥时候吃到面是一个随机问题一般情况下这是没有问题的~~~ 注意当我们每个哲学家左手拿起筷子时可以发现此时每个哲学家都吃不到面吃面要两根筷子都等待另一个哲学家释放筷子锁此时就发生了线程的阻塞  3.2解决死锁的方法 在了解线程的解决死锁之前我们要知道产生死锁的必要条件 重点 1.互斥使用当一个线程获取到锁之后另一个线程也想要获取那么此时就要进行阻塞 2.不可抢占当一个线程获得锁之后其他线程想要获取此时就要等到锁的释放不能强行占用 3.请求保持当一个线程获得锁A之后尝试再次获取锁B锁A是没有释放的 4.循环等待/环路等待 以上就是死锁形成的必要条件缺一不可~~~ 那么针对以上死锁的产生条件第三个条件是根据具体的代码来进行实现的但是我们可以根据最后一个来进行攻破 注意解决哲学家问题关键针对五把锁我们可以对其进行编号然后每个哲学家也进行编号此时约定每个哲学家开始只能够拿编号比自己小的锁然后再拿比自己编号大的锁  为啥能够解决死锁问题呢且看下图所示 过程解释当我们为这个线程和锁进行编号后此时由于只能拿比自己编号小的筷子那么2号哲学家拿1筷子3号哲学家拿2号筷子.......到最后5号哲学家拿4号筷子此时就可以发现多了一双筷子那么5号哲学家先再拿起5号筷子此时当5号哲学家吃完后放下筷子一次类推可以保证每个哲学家都拿够吃到面~~~同理这就解决了死锁这个问题 那么此时我们就可以改变之前这个双方获取两个锁的这个代码实现这个代码的可行性 Thread t2new Thread(()-{synchronized (A) {System.out.println(线程t2拿到了锁A);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException();}//线程进入休眠保证另一个线程也能够拿到锁//尝试拿到对方的锁没有释放自己的锁synchronized (B) {System.out.println(线程t2拿到了两把锁);}}}); 注意这里小编只改了第二个线程的获取锁的顺序即可保证两个线程都能够拿到锁 解析这里能够执行原因当两个线程启动的时候线程1获取到了锁A所以此时线程B规定先不获取锁即他以获取锁A来发生阻塞当线程1执行完后线程2就能够得到两个线程了~~~这就是引入了加锁顺序规则~~~ 总结 解决死锁有很多办法以下是一些小编总结的一些方法 1.添加“筷子” 2.去掉一个线程 3.引入计数器规定最多同时几个人吃面 4.引入加锁顺序规则 5.“银行家算法” 1~3虽然能够解决这个问题但是普适性不高 4是小编推荐的普适性高而且容易实现 5是可以解决这个死锁问题但是不推荐实现过程很复杂理论成立现实不行 ️4.内存可见性 4.1内存可见性实例 内存可见性问题即一个程序读一个程序写的过程中产生的线程安全问题 小编就用代码实例来演示 public static void main(String[] args) {Thread t1new Thread(()-{while (flag0){//不输出任何 }System.out.println(flag的值进行了改变);});Thread t2new Thread(()-{System.out.println(输入一个flag的值);Scanner scannernew Scanner(System.in);flagscanner.nextInt();});//起启动线程t1.start();t2.start();} 解释此时我们规定线程1进行读的操作若flag是0那么就不会打印任何日志此时小编在线程2上进行改变线程1中flag的值让其不满足条件实现跳出循环结束线程但是输出如下 可以发现在小编输入1改变flag的值之后回车并没有输出“flag的值进行了改变”所以此时就发生了线程安全问题即内存可见性问题~~~ 4.2内存可见性原理 这里从核心指令入手 while (flag0){//不输出任何 } 注意这里的核心指令有两条 1.load读取内存当中的指令到寄存器中 2.寄存器拿着值与0进行比较 那么此时就是在线程2启动到输入这个操作不断进行循环读取比较的过程所以这个操作有两个关键要点 1.load不断从内存中读取数据到CPU寄存器上这个操作的执行结果是一样的几秒之内已经很多次了~~~ 2.load从内存中读取数据这个操作开销远远大于寄存器比较这个操作~~~ 此时就出现了一个问题编译器优化代码这个操作即JVM在优化中发现读取数据操作一直不变那么优化后即将这个load读取数据操作给省去了关键原因  代码优化即JVM在保持原有代码逻辑不变的情况下实现提高代码的效率单线程还好但是多线程很容易发生误判~~~ 4.3内存可见性解决 1.进行线程休眠 核心在上述讲解中是因为读取这个内存的次数过多且没有改变所以我们能够实现读取次数减少的操作 代码实现如下 Thread t1new Thread(()-{while (flag0){//不输出任何try {Thread.sleep(1000);}catch (InterruptedException e){e.printStackTrace();}}System.out.println(flag的值进行了改变);}); 小编只需要在读取数据这个操作实现休眠即可 注意这里的休眠是为了减少从内存中读取数据到CPU寄存器上让load开销减少减少迫切优化的程度此时JVM就不会进行优化了那么就不会出现线程安全问题 2.添加volatile关键词  volatile作用这里的volatile关键词会阻止JVM对程序进行优化确保每次循环都会从内存中读取数据到寄存器当中~~~ volatile核心作用解决内存可见性问题和禁止指令重排序~~~ 代码演示 public volatile static int flag0; //加上volatile实现代码优化的消除public static void main(String[] args) {Thread t1new Thread(()-{while (flag0){//不输出任何 }System.out.println(flag的值进行了改变);}); 注意volatile和上述休眠作用基本一致都是使JVM优化程序关闭保证每次循环都是从内存中读取数据而不是优化成直接从寄存器当中读取数据~~~ ️5.总结 本期小编总结了关于多线程的重要知识即死锁分别从造成原因和如何进解决提出了关于小编的理解以及线程安全问题之内存可见性问题并附上了代码供小伙伴们参考参考~~~ ~~~~最后希望与诸君共勉共同进步 以上就是本期内容了 感兴趣的话就关注小编吧。 期待你的关注~~~
http://www.hkea.cn/news/14308353/

相关文章:

  • 黑龙江生产建设兵团知识网站工商网站查询企业信息武威
  • 艺术公司网站定制7天精通网站建设实录简介242
  • 网站栏目页面公司做一个网站如何定位
  • 商城网站建设公司哪家好wordpress调整配置文件
  • 网站建设要固定ip网络吗4435建站
  • 如何查看网站抓取频率洪山网站建设
  • 松江区做网站外贸wordpress模板下载
  • 超简洁网站wordpress添加vip角色
  • 建设网站需要什么手续网上订货发货网站建设
  • 合作网站账号登录方式房地产开发公司取名
  • 建设项目环境影响登记网站天津网站建设课程中的收获
  • 做爰片的网站关于解决网站 建设的请示
  • 专门做金融的招聘网站国外炫酷网站
  • 临沭县住房和城乡建设局网站安卓编程软件app
  • 中国空间站完成图集团网站建设要多少钱
  • 做个人网站怎么做手机平面设计软件
  • 厦门本地企业网站建设免费的网站入口在哪
  • 百度上做网站免费吗广东圆心网站开发
  • 南通 外贸建站中国建筑装饰网官网
  • 吉林省建设厅证件查询网站番禺免费核酸检测
  • 做导购网站需要多大的服务器软件开发文档说明
  • wordpress 教育 主题seo优化百度seo谷歌seo外贸推广网站seo优化运
  • 做网站在经营范围内属于什么魅姬直播
  • 做网站600广告网站素材
  • 佛山网站建设哪个好免费云虚拟主机
  • 网站开发工具 枫子科技永州做网站
  • 网络科技网站排名网页设计尺寸大小指的是什么
  • 可信网站必须做吗手机如何免费做网站
  • 自己建网站做电商还赚钱吗建手机网站款软件
  • 望都网站建设网站直播软件开发