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

石家庄大型网站建设化妆品品牌策划方案

石家庄大型网站建设,化妆品品牌策划方案,海淀高端网站建设,成免费的crm图片目录 1.线程的状态 1.1 NEW、RUNNABLE、TERMINATED 1.2 TIMED_WAITING 1.3 WAITING 1.4 BLOCKED 2.多线程带来的风险-线程安全#xff08;重点#xff09; 2.1 观察线程不安全的现象 2.2 分析产生该现象的原因 2.3 产生线程安全问题的原因 2.3.1 抢占式执行#x…目录 1.线程的状态 1.1 NEW、RUNNABLE、TERMINATED 1.2 TIMED_WAITING 1.3 WAITING 1.4 BLOCKED 2.多线程带来的风险-线程安全重点 2.1 观察线程不安全的现象 2.2 分析产生该现象的原因 2.3 产生线程安全问题的原因 2.3.1 抢占式执行根本 2.3.2 多个线程同时修改同一个变量 2.3.3 修改操作不是原子的 2.3.4 内容可见性问题 2.3.5 指令从排序 2.4 如何解决线程安全问题 2.4.1 抢占式执行 2.4.2 多个线程同时修改同一个变量 2.4.3 修改操作不是原子的 2.4.3.1 锁的概念 2.4.3.2加锁synchronized 2.4.3.3 synchronized的变种写法 2.4.3.4 可重入 2.4.3.5 监视器锁 1.线程的状态 线程的所有状态如下 • NEW: 安排了⼯作, 还未开始⾏动 • RUNNABLE: 可⼯作的. ⼜可以分成正在⼯作中和即将开始⼯作. • BLOCKED: 这⼏个都表⽰排队等着其他事情 • WAITING: 这⼏个都表⽰排队等着其他事情 • TIMED_WAITING: 这⼏个都表⽰排队等着其他事情 • TERMINATED: ⼯作完成了. 1.1 NEW、RUNNABLE、TERMINATED 对于这三个状态的解释 NEWnew了Thread对象还没start RUNNABLE 就绪状态可以分成以下两种情况正在工作或者即将开始工作 1线程正在cpu上执行 2线程随时可以去cpu上执行 TERMINATED内核中的线程已经结束了但是Thread对象还在 public static void main(String[] args) throws InterruptedException {Thread t1new Thread(()-{System.out.println(线程t1开始执行...);try {Thread.sleep(1);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(t1线程结束...);});System.out.println(t1.getState());t1.start();Thread.sleep(0,500);System.out.println(t1.getState());t1.join();System.out.println(t1.getState());} 执行结果 1.2 TIMED_WAITING • 指定时间的阻塞 • 线程阻塞不参与 cpu 调度不继续执行了 • 阻塞的时间是有上限的 Thread.sleep(时间);会进入到TIMED_WAITING状态 另外join(时间)也会进入到TIMED_WAITING状态 1.3 WAITING 死等没有超时时间的阻塞等待 1.4 BLOCKED 也是一种阻塞比较特殊是由于锁导致的阻塞。 2.多线程带来的风险-线程安全重点 2.1 观察线程不安全的现象 案例 创建一个静态变量count0; 在main方法里创建两个线程t1和t2 两个线程内分别循环五万次count操作 最后打印出count的值 public class Demo10 {public static int count0;public static void main(String[] args) throws InterruptedException {Thread t1new Thread(()-{for (int i 0; i 50000; i) {count;}});Thread t2new Thread(()-{for (int i 0; i 50000; i) {count;}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);} } 按照道理来说count进行了总共十万次count操作打印出来的值应该是十万实际上却并非如此执行代码 这样的代码很明显是有bug的实际执行效果与预期效果不符合就叫做bug。 这样的问题是多线程并发执行引发的问题。 如果调换代码的执行程序把t1线程和t2线程的并行改成串行一个执行完了再执行另一个 结果又变成正确的了 执行结果 很明显当前的bug是由于多线程的并发执行代码引起的bug 这样的bug就称为“线程安全问题”或者叫做“线程不安全” 反之如果一个代码在多线程并发执行的环境下也不会出现类似上述的bug 这样的代码就称为“线程安全” 2.2 分析产生该现象的原因 站在 CPU 的角度来看count这个操作看起来是一行代码实际上对应到三个CPU指令 1.load把内存中的值count变量读取到寄存器中 2.add把指定的寄存器中的值进行1操作结果还是在这个寄存器中 3.save把寄存器中的值写回到内存中 CPU执行这三条指令的过程中随时有可能触发线程的调度切换如下所示 指令1 指令2 指令3 线程切走 指令1  指令2  线程切走  指令3 指令1 线程切走 指令2 指令3 指令1 线程切走 指令2 线程切走 指令3 但是由于操作系统的调度是随机的不可预期的 执行任何一个指令的过程中都有可能触发上述的“线程切换”的操作 也就是说随机调度或者叫抢占式执行就是线程安全问题的罪魁祸首。 t1线程和t2线程的执行过程可能会出现如下情况只举了个别例子可能还有别的情况 对于执行结果打 √ 的为正确结果× 为错误结果。 对于其中某种正确情况的具体执行过程如下 对于其中某种错误情况的具体执行过程如下 可以看到 t1线程和t2线程分别进行了一次count操作理论上count的值应为2实际上由于随机调度t1的寄存器和t2的寄存器都读取了内存的初始值0最终执行完两次count后count的值为1 由于线程执行的过程中有可能大概率会发生上述的错误情况因此代码的执行结果总是100000 如果降低单个线程的循环次数会发现能运行出正确的结果 运行结果 出现这种现象的原因 事实上线程安全问题依旧存在只不过概率变低了。 单个线程执行的count次数会影响到这个线程的运行时间即运行50次比运行50000次要快得多 因为运行的太快了很可能在t2.start()执行之前t1线程就执行完了 等到后续t2线程的执行就变成了串行执行 2.3 产生线程安全问题的原因 2.3.1 抢占式执行根本 抢占式执行操作系统对于线程的调度是随机的 抢占式执行策略 最初诞生于多任务操作系统的时候是非常重大的发明 后世的操作系统都是一脉相承 2.3.2 多个线程同时修改同一个变量 如果是一个线程修改一个变量---没问题 如果是多个线程不是同时修改同一个变量---没问题 如果是多个线程修改不同变量---没问题不会出现中间结果相互覆盖的情况 如果是多个线程读取同一个变量---没问题该变量不可修改 2.3.3 修改操作不是原子的 原子 如果一个操作只是对应到一个cpu指令那么就可以认为它是原子的 cpu就不会出现“一条指令执行到一半”这样的情况 反之如果一个操作对应到多个cpu指令那么它就不是原子的例如 -- - ........ 2.3.4 内容可见性问题 后续再讨论 2.3.5 指令从排序 后续再讨论 2.4 如何解决线程安全问题 2.4.1 抢占式执行 抢占式执行是操作系统的底层设定程序员无法左右。 2.4.2 多个线程同时修改同一个变量 和代码的结构直接相关 可以调整代码结构规避一些线程不安全的代码 但是这样的方案不够通用 Java中有个东西 String 就是采用了“不可变”特性确保线程安全 2.4.3 修改操作不是原子的 解决方案 Java中解决线程安全问题最主要的方案就是加锁 通过加锁操作让不是原子的操作打包成一个原子的操作 2.4.3.1 锁的概念 计算机中的锁和生活中的锁是同样的概念互斥/排他 把锁“锁上”称为“加锁” 把锁“解开”称为“解锁” 一旦把锁加上了其他人要想加锁就得阻塞等待 对于上述例子的count操作它并非是原子的此时就可以使用锁把刚才不是原子的count 包裹起来在count之前先加锁然后进行count计算完毕之后再解锁 此时在执行三步走的过程中其他线程就没法“插队”了 加锁操作不是把线程锁死到cpu上禁止这个线程被调度走 而是禁止其他线程重新加这个锁避免其他线程的操作在当前线程执行的过程中“插队” 2.4.3.2加锁synchronized 加锁 / 解锁 本身是操作系统提供的api 很多编程语言都对这样的api进行了封装 大多数的封装风格都是采取两个函数 加锁 lock(); //执行一些要保护起来的逻辑 解锁 unlock(); Java中使用 synchronized 这样的关键字搭配代码块来实现类似的效果 synchronized(){ //进入代码块相当于加锁 //执行一些要保护起来的逻辑 }出了代码块相当于解锁 使用synchronized对上述案例进行加锁 可以看到括号内需要填入参数应该填入什么呢 填写的是用来加锁的对象。要 加锁 / 解锁前提是得先有一个锁 在Java中任何一个对象都可以用作“锁” 这个对象的类型是什么不重要 重要的是是否有多个线程针对这同一个对象加锁竞争同一把锁 再次执行代码线程安全问题得到了解决 【注意】 两个线程针对同一个对象加锁才会产生互斥效果 一个线程加上了锁另一个线程就得阻塞等待等到第一个线程释放锁才有机会 如果是不同的锁对象此时不会有互斥效果线程安全问题并没有得到解决 代码执行结果依旧存在线程安全问题 2.4.3.3 synchronized的变种写法 在方法内加锁 这种写法跟之前的写法产生的效果是一样的执行代码 修饰方法的写法还能继续变形使用synchronized修饰方法就相当于是针对this进行加锁 这种写法跟上面的效果也是一样的。 StringBuffer、Vector这些类里面有些方法就是带有synchronized的 因此StringBuffer是线程安全的而StringBuilder线程不安全。 而方法之中还有一个特殊情况static修饰的方法不存在this 此时synchronized修饰static方法相当于针对类对象加锁。 2.4.3.4 可重入 当我们使用锁写代码一旦方法调用的层次比较深搞不好就会出现这种情况或者类似的 分析上面这段代码 1.第一次进行加锁第一层能够成功锁没有人使用 2.第二次进行加锁第二层此时的locker已经是被占用的状态第二次加锁就会触发阻塞等待 要想解除阻塞就必须往下执行 要想往下执行就需要等到第一次的锁被释放 这样的问题就被称为“死锁”(dead lock) 为了解决上述问题Java的synchronized就引入了可重入的概念 当某个线程针对一个锁加锁成功之后 后续该线程再次针对这个锁进行加锁 不会触发阻塞而是直接往下走 因为当前这把锁就是被这个线程持有 但是如果是其他线程尝试加锁就会正常阻塞 也就是说当我们执行上述代码时并不会触发死锁而是正常执行 可重入锁的实现原理关键在于让锁对象内部保存当前是哪个线程持有这把锁 后续有线程针对这个锁加锁的时候对比一下持有锁的线程是否和当前要加锁的线程是同一个 当有多层加锁时最外层的加锁和解锁才是有效的内部锁直接放行 站在JVM的角度看到多个 } 需要执行JVM如何知道哪个 } 是真正需要解锁的那个 先引入一个变量计数器0 每次触发 { 的时候把计数器 每次触发 } 的时候把计数器-- 当计数器 --到0的时候就是真正需要解锁的时候 2.4.3.5 监视器锁 监视器锁 minitor lock JVM中采用的一个术语 使用锁的过程中抛出的一些异常可能会看到 监视器锁 这样的报错信息 完 如果哪里有疑问的话欢迎来评论区指出和讨论如果觉得文章有价值的话就请给我点个关注还有免费的收藏和赞吧谢谢大家
http://www.dnsts.com.cn/news/61163.html

相关文章:

  • 苏州网站设计电话淘宝店铺如何推广
  • 网站突然被降权怎么办万网ip查询
  • 怎么用公司网站做公司域名多个杭州小型网站建设服务
  • 家具公司网站模板下载wordpress标题写法
  • 展示型商城订单网站建设wordpress翻译公司
  • 上海高端网站定制开发如何建立公司网站建议和规则
  • 文件上传网站源码百度竞价推广优势
  • 新干做网站广州专业做网站建设
  • 盐城网站设计重庆施工许可证查询
  • 中山本地网站建设dw网页设计位置1
  • 米卓网站建设二十个优化
  • 网站群建设代理我为什么不建议年轻人做运营
  • 山东网站开发网络公司生活信息网站如何推广
  • 淮南做网站推广asp.net 大网站
  • 河北网站建设与制作北京网站建设推广服务信息
  • 南京建设局网站开发网站的工具有哪些
  • 自学编程网站遵义建一个网站大概要多少钱
  • 智云鸟网站建设官方网站下载6966
  • 建设直播网站需要哪些许可证网站建设策划模板
  • 空间链接制作网站淮安哪里有做网站的
  • ps里面怎么做网站对联广告centos 7 安装wordpress
  • 建立淘宝客网站用什么软件做网站最好
  • 成都建设局网站网站建设毕业设计模板
  • 网站建设的目的和目标在线代码编辑器
  • 旅游社做的最好的网站南宁设计网站
  • 怎样在网站上做链接精通网站建设pdf下载
  • 网站建设需要什么软件有哪些网站下拉菜单设计
  • 网站建设实训室介绍wordpress 输出json
  • 南通网站建ui培训哪里好
  • 域名同时做邮箱和网站微网站如何建设方案