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

朔州市住房与城乡建设厅网站酒店vi设计

朔州市住房与城乡建设厅网站,酒店vi设计,鞋 东莞网站建设 技术支持,站点-将网站添加到区域变灰色无法添加如何解决提示#xff1a;文章写完后#xff0c;目录可以自动生成#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、synchronized的优化操作 1.1 锁膨胀/锁升级 1.2 锁消除 1.3 锁粗化二、JUC 2.1 Callable接口 2.2 ReentrantLock类… 提示文章写完后目录可以自动生成如何生成可参考右边的帮助文档  文章目录 前言一、synchronized的优化操作       1.1 锁膨胀/锁升级       1.2 锁消除       1.3 锁粗化二、JUC        2.1 Callable接口        2.2 ReentrantLock类可重入锁        2.3 原子类        2.4 Semaphore类信号量        2.5 CountDownLatch类三、线程安全的集合类        3.1 多线程使用顺序表        3.2 多线程环境使用队列        3.3 多线程环境使用哈希表前言 这篇博客主要介绍 synchronized 的底层工作原理包括锁膨胀/锁升级、锁消除、锁粗化 并且介绍了 关于JUC的详细知识点 以及一些线程安全的集合类 ; 一、synchronized的优化操作  由上一篇博客我们可以知道synchronized 使用的锁策略 有以下特点 既是悲观锁也是乐观锁自适应既是轻量级锁也是重量级锁自适应轻量级锁部分基于自旋锁实现重量级锁部分基于挂起等待锁来实现不是读写锁是非公平锁是可重入锁1.1 锁膨胀/锁升级 现在我们需要知道 synchronized 是怎样 自适应的?这个过程又叫做 锁膨胀/锁升级  synchronized 在加锁的时候要经历几个阶段 当线程没有加锁的时候这个阶段叫做 无锁;当线程刚开始加锁并没有产生竞争的时候这个阶段叫做 偏向锁;当线程进行加锁并且已经产生锁竞争了这个阶段叫做 轻量级锁;如果此时锁竞争的更激烈了这个阶段叫做 重量级锁;图示解析 当然这几个阶段并不是说 每一次加锁都会一直加到 最后可能会到某一阶段之后就会解锁了不会每一个阶段都会经历但会经历到某一部分 像上面的锁的状态不断的升级锁的竞争也逐渐加剧 的情况就叫做 锁膨胀/锁升级 这里就先重点介绍一下 偏向锁 所谓偏向锁并不是 真正加锁而是只使用一个标记表示 这个锁是我的了在遇到其他线程来竞争锁之前会一直保持着这个状态 直到真的有线程来竞争锁了此时才会真正的加锁 这个过程类似于 单例模式中的 懒汉模式 —— 在必要的时候进行加锁从而会节省一定的开销 因为如果没有额外的线程 来参与锁竞争的话那么就会一直处于偏向锁的状态也就省去了加锁和解锁的开销了 1.2 锁消除 synchronized 除了锁升级还有其他的优化操作比如说锁消除  所谓锁消除即 编译器自动锁定如果认为这个代码没必要加锁就不加了 代码举例 StringBuffer sb new StringBuffer(); sb.append(a); sb.append(b); sb.append(c); sb.append(d); //就比如说StringBuffer 是线程安全的它的 append 等方法都是带有synchronized, //如果上述代码 都只是在同一个线程里面执行的那么此时就没有必要加锁了 //此时JVM 就自动悄悄的把锁给去掉了(这也属于编译器优化的一个方面) 但是锁消除的操作 不是所有的情况下都会触发实际上大部分情况下不能被触发 而 向偏向锁 则是每一次加锁都会进入到偏向锁的状态 1.3 锁粗化 锁粗化也是 synchronized 的一种优化方式 在这之前我们需要知道 锁的粒度 这个概念 所谓 锁的粒度指的是 synchronized 包含的代码范围是大还是小 范围越大粒度越粗 范围越小粒度越细 锁的粒度越细能够更好的提高线程的并发但是也会增加 加锁解锁 的次数 锁粗化也是类似的情况它把一段代码中频繁的加锁解锁粗化 成一次加锁解锁了 图示分析  毕竟加锁解锁 也是需要开销的嘛  二、JUC 所谓 JUC实际上指的是java.util.concurrent它是一个包 在这个包里面 存放了很多和多线程开发 的相关的类、接口 2.1 Callable接口 Callable接口 和 前面的Runnable 非常相似都是可以在创建线程的时候来指定一个 具体的任务 区别是Callable 指定的任务是带返回值的Runnable 指定的任务是不带返回值的 Callable 提供的 call方法可以方便的获取到代码的执行结果     如创建线程计算 123 ... 1000使用Callable版本 代码示例 package thread;import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask;public class Demo29 {public static void main(String[] args) throws ExecutionException, InterruptedException {CallableInteger callable new CallableInteger() {Overridepublic Integer call() throws Exception {int sum 0;for (int i 1; i 1000; i) {sum i;}return sum;}};//套上一层目的是为了获取到后续的结果FutureTaskInteger task new FutureTask(callable);Thread t new Thread(task);t.start();//在 线程t 执行结果之前get会阻塞//直到 线程t 执行完了结果算好了get 才能返回返回值就是 call方法 return 的内容//获取执行结果System.out.println(task.get());} } 运行结果 需要重点理解的是 下面一部分代码  //给 计算结果 一个小票 FutureTaskInteger task new FutureTask(callable); 在线程需要计算结果的情况下需要非常明确的知道 这个结果是谁来算的不能像以前一样直接把 callable 加到 Thread 的构造方法之中之前使用 Runnable 的时候不需要知道一个明确的结果 就类似于去餐馆吃饭的时候人多的时候老板会给一个小票到时候就可以凭着小票来取餐不至于搞乱了 2.2 ReentrantLock类可重入锁 我们已经知道synchronized 已经是一个可重入锁了但是 为啥还要再搞一个 ReentrantLock 呢  实际上ReentrantLock 还是和 synchronized 之间有很大的差别的 1.synchronized 是一个单纯的关键字以代码块为单位进行加锁解锁ReentrantLock 则是一个类提供 lock方法 加锁unlock方法 解锁  2.ReentrantLock 在构造实例的时候可以指定一个 fair参数 来决定锁对象是 公平锁还是非公平锁synchronized 加的锁只能是非公平锁不能指定为公平锁 3.ReentrantLock 还提供了一个特殊的加锁操作 —— tryLock() 方法 4.ReentrantLock 提供了更加强大的 等待/唤醒 机制  说明大部分情况下使用锁还是以 synchronized 为主特殊场景下才使用 ReentrantLock  2.3 原子类 原子类内部用的是 CAS 实现的所以性能要比加锁实现 i 高很多 原子类有以下几个 AtomicBooleanAtomicIntegerAtomicInterArrayAtomicLongAtomicReferenceAtomicStampedReference举例说明 以 AtomicInteger 为例常见方法有 addAndGet(int delta); i delta; decrementAndGet(); --i; getAndDecrement(); i--; incrementAndGet(); i; getAndIncrement(); i; 2.4 Semaphore类信号量  所谓信号量可以理解成 计数器描述了可用资源的个数; 举例说明 比如说停车场的入口处会有牌子上面显示当前有车位 N 个 当有车开进去以后N 就会减去一个当有车从出口开出去以后N 就会加上一个 这个 N 就叫做 信号量 如果当前 N 已经是 0 了如果还有车想进来那就进不去了新来的车只能阻塞等待直到有车给开出去 如上所示 把车开进去称之为 申请一个可用资源信号量 - 1称为 P 操作 把车开出来称之为 释放一个可用资源信号量 1称为 V 操作 其实信号量 可以把它视为一个 更广义的锁当信号量的取值是 0~1 的时候就退化成了一个普通的锁 锁 相当于是一个可用资源是 1 的信号量只要加锁成功其他的线程就获取不了 但是信号量不一样只要可用资源还有就可以不断的进行 P 操作 说明我们需要知道上面的信号量 1-1 都是原子的 代码演示 package thread;import java.util.concurrent.Semaphore;public class Demo31 {public static void main(String[] args) throws InterruptedException {//构造方法传入有效资源的个数是 3 个Semaphore semaphore new Semaphore(3);//P操作 申请资源使用 acquire方法//每一次使用一个资源信号量 -1semaphore.acquire();System.out.println(申请资源);semaphore.acquire();System.out.println(申请资源);semaphore.acquire();System.out.println(申请资源);semaphore.acquire();System.out.println(申请资源);} }  运行结果 有效资源是 3 份即使 想要申请4份资源但是在运行结果中显示最终只是申请了 3 份资源 只有前面的线程把资源释放了才可以使用 代码示例 package thread;import java.util.concurrent.Semaphore;public class Demo31 {public static void main(String[] args) throws InterruptedException {//构造方法传入有效资源的个数是 3 个Semaphore semaphore new Semaphore(3);//P操作 申请资源使用 acquire方法//每一次使用一个资源信号量 -1semaphore.acquire();System.out.println(申请资源);semaphore.acquire();System.out.println(申请资源);semaphore.acquire();System.out.println(申请资源);//V操作 释放资源使用 release 方法//此时信号量 0,线程进入阻塞只有释放资源线程才可以继续运行semaphore.release();System.out.println(释放资源成功);semaphore.acquire();System.out.println(申请资源成功);} } 运行结果 2.5 CountDownLatch类  CountDownLatch类相当于 在一个大的任务被拆分成若干个子任务的时候用这个来衡量 什么时候这些子任务都执行结束 举个例子 此时在某地正在进行一场跑步比赛只有当所以选手都到达终点的时候裁判才可以吹哨结束比赛 CountDownLatch 描述的就是啥时候所有选手都到达终点 代码示例 package thread;import java.util.concurrent.CountDownLatch;public class Demo32 {public static void main(String[] args) throws InterruptedException {//模拟跑步比赛//构造方法中设定有 10 个选手参赛CountDownLatch latch new CountDownLatch(10);for (int i 0; i 10; i) {Thread t new Thread(() - {try {Thread.sleep(3000);System.out.println(Thread.currentThread().getName() 到达终点);//countDown 相当于 撞线latch.countDown();} catch (InterruptedException e) {e.printStackTrace();}});t.start();}//await 再等待所有的线程都 撞线//换句话说调用 countDown 的次数达到初始化的时候 设定的值//await 就返回否则 await 就阻塞等待latch.await();System.out.println(比赛结束);} } 运行结果 三、线程安全的集合类 原来的集合类大部分都是 线程不安全的 换句话来说大部分集合类在多线程环境下使用 都是有问题的 总结 ArrayList、LinkedList、TreeSet、TreeMap、HashSet、HashMap、Queue 是线程不安全的 Vector、Stack、HashTable 是线程安全的 3.1 多线程使用顺序表  一自己使用加锁操作 二使用 Collections.synchronizedList (new ArrayList); synchronizedList 是标准库提供的一个基于 synchronized 进行线程同步的 List synchronizedList 的关键操作上都带有 synchronized 三使用 CopyOnWriteArrayList 如果出现修改操作就把 Ar rayList 进行复制 ; 先拷贝一份数据创建一份副本再接着新线程修改副本修改完成后再用副本替换原有的数据 ; 这就叫做 写实拷贝 ; 不过这种行为的 拷贝成本可能会很高所以 一般元素个数多的时候会用到 ; 3.2 多线程环境使用队列  多线程环境下常常使用以下阻塞队列 ArrayBlockingQueue 基于数组实现的阻塞队列;LinkedBlockingQueue 基于链表实现的阻塞队列;PriorityBlockingQueue 基于堆实现的带优先级的阻塞队列;TransferQueue 最多只包含一个元素的阻塞队列;3.3 多线程环境使用哈希表  HashMap本身不是线程安全的在多线程环境下可以使用 HashTableConcurrentHashMapHashTable 其中HashTable 直接搞了一个大锁这就导致了 在多个线程去修改上面的元素 的时候都需要去进行加锁控制就会有锁冲突比较低效  对于两个不同的哈希桶上的元素不牵扯修改同一个变量就不会发生线程安全问题此时加锁的话意义不大 但是如果两个修改涉及到同一个哈希桶上就会有线程安全问题 ; 于是HashTable 就会显得低效 ; ConcurrentHashMap 相比之下ConcurrentHashMap类 做出了重大的改进 —— 把锁的粒度细化了 接下来介绍的 ConcurrentHashMap类 基于 java 1.8 的 ; 该类是基于哈希表中的每一个链表对象进行加锁线程需要对哪个链表对象进行操作就在哪里加锁; 由于哈希表中链表数量很多链表对象的元素个数较少可以有效地降低锁竞争的概率 ; ConcurrentHashMap 优化特点 [ 最重要 ] 把锁的粒度细化降低锁冲突的概率; 有一个激进的操作读没加锁写才加锁; 更充分的使用了 CAS 特性达到一个更高效的操作如 维护 size 的时候; 针对扩容场景进行了优化化整为零不会一口气的完成扩容而是 每次基本操作都扩容一点点逐渐完成整个扩容 —— 不会特别卡;  总结 今天的关于多线程( 进阶篇 ) 锁的优化、JUC的常用类、线程安全的集合类就讲到这里我们下一节内容再见
http://www.dnsts.com.cn/news/16346.html

相关文章:

  • 自学搭建网站wordpress无法连接ftf服务器
  • 公众号开发源码佛山企业推广优化
  • wordpress适合视频网站吗贵阳网站建设黔搜
  • 宁夏网站设计联系电话百度seo原理
  • dedecms 做的医院网站jsp网站服务建设开题报告
  • 建站行业现状探讨专门找事做的网站
  • 大唐网站首页青岛房产网上查询
  • 网站需求表格网站建设与设计教程
  • 2018做网站用什么开发怎么做卖保险的网站
  • 莱芜网站建设流程百度改网站描述
  • html情人节给女朋友做网站怎样查询网站的备案号
  • 2013影响网站百度搜索排名的关键因素统计百度网站降级的原因
  • 建设网站赚钱昆明高端网站建设
  • 如何在百度云上建设网站绩溪建设银行网站
  • 网站忧化工作怎么样曰本免费一级a做爰视频网站
  • 建设网站需要营业执照吗青岛博海建设网站
  • 视频在线观看网站怎么建设郑州妇科医院哪家排名比较好
  • 大理旅游网站建设什么网站可以找人做软件下载
  • 咸阳网站开发公司电话装修计算器在线计算
  • 《网页制作与网站建设》wordpress 分享后阅读
  • 网站三层结构示意图企业邮箱注册需要什么材料
  • 陕西建设网站官网做百度词条需要哪些网站
  • 哈尔滨网站建设网站开发企业网页设计价格
  • 公司做网站自己注册域名做效果图网站
  • 用服务器建立网站教程网络公司经营范围包括劳务吗
  • 随州哪里学做网站网站编辑是个长期做的工作吗
  • 青岛房产网站公司网站制作计入什么科目
  • 如何在路由器上做网站转跳个人怎么做ipv6的网站
  • 温州网站建设对比泉州那几个公司网站建设比较好
  • 做哈尔滨本地门户网站赚钱吗小程序发布流程怎么弄