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

学科网站建设方案免费收录软文网站

学科网站建设方案,免费收录软文网站,新手网站建设教程,建网站域名注册后需要1.背景并发程序开发不可避免地要涉及多线程、多线程协作、数据共享和线程安全等问题。在多线程并发场景下#xff0c;由于采用数据共享的线程通信模型可能导致多个线程之间并发时相互干扰#xff0c;影响到程序的正常逻辑、无法保证正常的结果。为了保证程序在并发环境的正确…1.背景并发程序开发不可避免地要涉及多线程、多线程协作、数据共享和线程安全等问题。在多线程并发场景下由于采用数据共享的线程通信模型可能导致多个线程之间并发时相互干扰影响到程序的正常逻辑、无法保证正常的结果。为了保证程序在并发环境的正确性有必要对多线程并发进行防范因此就有了并发控制机制。Java并发控制机制并发防范机制等价于并发控制机制同步有序机制可以说是并发防范的一个子集。Java并发提供了多个维度的并发防范机制。我们可划分JVM、JDK 2个层面JVM层面主要指关键字同步原语volatile、synchronized、final。通过字节码指令禁止指令重排序来保证顺序一致性。JDK层面是JUC并发包比如基于队列同步器实现的重入锁RetrantLock、读写锁ReentrantReadWriteLock此外还有Semaphore、CountDownLatch、CyclicBarrier等并发工具本质还是锁、原子操作类比如AtomicInteger、ThreadLocal线程局部变量无锁防并发方案、线程安全的并发容器ConcurrentHashMap、BlockingQueue等。关于线程安全“线程安全”网上大部分的解释是如果一个对象可以安全地被多个线程同时使用那它就是线程安全的。并不能说它不对但是不够精确几乎获取不到什么有用信息。《Java Concurrency In Practice》的作者Brian Goetz为“线程安全”做出了一个比较恰当的定义当多个线程同时访问一个对象时如果不用考虑这些线程在运行时环境下的调度和交替执行也不需要进行额外的同步或者在调用方进行任何其他的协调操作调用这个对象的行为都可以获得正确的结果那就称这个对象是线程安全的。”这个定义就很严谨而且有可操作性它要求线程安全的代码都必须具备一个共同特征代码本身封装了所有必要的正确性保障手段如互斥同步等令调用者无须关心多线程下的调用问题更无须自己实现任何措施来保证多线程环境下的正确调用。这点听起来简单但其实并不容易做到。2.JVM同步机制volatilevolatile关键字的并发安全性承诺即声明为volatile的变量可以做到线程对volatile变量的修改可以及时反应到其他线程对volatile变量的写入可以及时作用到主内存其他线程读取volatile变量也是直接从主内存读取。volatile变量的读写有序性JVM通过字节码指令enterexit禁止指令重排序来保证有序性即两线程并发使volatile变量的写入总是先行发生于对volatile变量的读取。以上描述的是volatile变量在多个线程间的可见性和有序性禁止指令重排序说到底volatile变量需要保证volatile写/读顺序volatile重排序规则表如下(JSR-133)首先若第二个操作是volatile写则不允许指令重排序。其次若第一个操作是volatile读同样不允许指令重排序。最后当第一个操作是volatile写第二个操作volatile读则不允许指令重排序。那么volatile具体是如何做到的为了实现volatile的内存语义JVM采用基于保守策略的JMM内存屏障插入策略。在每个volatile写操作前面插入StoreStore屏障、在每个volatile写的后面插入StoreLoad屏障。在每个volatile读操作后面插入LoadLoad屏障、在每个volatile读的后面插入LoadStore屏障。基于保守策略可保证在任意平台、任意程序都得到正确的volatile语义。通过加入屏障可以保证volatile写-读与锁的释放-获取具有相同的内存效果锁的释放总是先行发生于获取锁同理volatile写总是先行发生于volatile读。synchronizedsynchronized是内部锁也叫重量级锁实际上1.6后它做过优化没那么重量级了是Java最重要的同步机制之一。虽然synchronized可以保证对象和代码段的线程安全但仅通过synchonized还不足以控制拥有复杂逻辑的线程交互为了实现多线程交互还需要和object的wait()和notify()两个方法联合使用。synchronized(obj) {while(?) {obj.wait()// 收到通知后继续执行} }synchronzied配合wait()、notify()是并发编程的基本技能之一。synchronized关键字的并发安全性承诺临界区互斥执行。锁的释放先行发生于锁的获取的内存语义。synchronized是如何做到互斥和保证先行发生关系的Java中每个对象都可以作为锁对象的锁。普通同步方法锁是当前实例对象静态同步方法锁是当前类的Class对象同步方法块锁是synchronized括号里配置的对象。这些实例对象、Class对象、配置的对象在锁范畴内叫Monitor对象。 JVM基于进入和退出Monitor对象来实现临界区互斥执行和锁的释放先行发生于锁的获取的内存语义。代码块同步使用monitorenter和monitorexit指令实现。同步方法是通过检查方法是否标志ACC_SYNCHRONIZED实现。锁优化方案1自旋首先分析一下synchronized的性能瓶颈。互斥同步对性能影响最大的是阻塞的实现。线程阻塞和用户态内核态转换带来的性能开销。虚拟机团队注意到在大部分应用共享数据的锁定状态只会持续很短一段时间如果在这个很短的共享数据锁定状态去挂起和恢复线程是划不来的对于多处理器系统当发现共享资源被锁定后能否让这个线程稍等一会儿但不放弃处理器执行时间呢答案是肯定的方案可行前提是共享资源很快会被释放。我们只需要让线程执行一个忙等待自旋这就是自旋锁的由来。我们可以通过-XX:UseSpinning开启自旋锁。其次自旋锁不能替代阻塞自旋锁对处理器有要求即多处理器虽然避免了阻塞但会占用CPU执行时间如果锁定很短效果会很好但如果锁定很长呢那是否就白白浪费的处理器执行时间了。因此自旋的等待时间必须有一个限度如果自旋超过了限定次数仍然没有成功获得锁就应该使用传统方式挂起线程。在虚拟机默认设置中自旋次数是10次可通过参数-XX:PreBlockSpin来更改。最后不过无论是默认值还是用户指定的自旋次数对整个Java虚拟机中所有的锁来说都是相同的。在 JDK 6中对自旋锁的优化引入了自适应的自旋。自适应意味着自旋的时间不再是固定的了而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定的。如果在同一个锁对象上自旋等待刚刚成功获得过锁并且持有锁的线程正在运行中那么虚拟机就会认为这次自旋也很有可能再次成功进而允许自旋等待持续相对更长的时间比如持续100次忙循环。另一方面如果对于某个锁自旋很少成功获得过锁那在以后要获取这个锁时将有可能直接省略掉自旋过程以避免浪费处理器资源。有了自适应自旋随着程序运行时间的增长及性能监控信息的不断完善虚拟机对程序锁的状况预测就会越来越精准虚拟机就会变得越来越“聪明”了。a.Java对象头和MarkWord设计首先synchronized用的锁是存在Java对象头里的对象如果是数组类型则JVM用3个字宽一个字宽32bit存储对象头如果对象是普通类型则使用2字宽。Java对象头组成如下所示下面我们看下Mark Word的字段组成情况。首先在无锁状态下32bit Mark Word划分如下在运行期Mark Word存储的数据会随着标志位的变化而变化如下所示以上是32位虚拟机的Mark Word字段分配。注无锁状态的Mark Word当有线程获取Monitor对象时会拷贝到栈帧的锁记录中。b.锁的升级过程锁膨胀从以上分析我们知道锁有4种状态无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态。这几种状态随着竞争情况而逐渐升级。锁只能升级而不能降级只所以这样做是为了提高获取锁和释放锁的效率。偏向锁Hotspot作者发现大多数情况下锁不仅不存在多线程竞争而且只是由同一线程获取为了让线程获取锁的代价更低而引入了偏向锁。当一个线程访问同步块时首先会判断锁的状态如果是01且允许偏向则进入第2步否则进入第4步。获取锁在对象头和栈帧中的锁记录里存储锁偏向的线程ID以后该线程在进入和退出同步块时不需要进行CAS操作来加锁和解锁只需要简单测试一下对象头Mark Word是否存储了指向当前线程的偏向锁。如果偏向锁没有设置且此时锁标志位为01则尝试CAS设置偏向锁。偏向锁的撤销使用了一种等待竞争出现才释放锁的机制当有其它线程竞争锁时持有偏向锁的线程需要等待全局安全点没有正在执行的字节码这个点它会暂停拥有偏向锁的线程判断线程的活跃状态如果不活跃则设置为无锁状态否则升级。轻量级锁轻量级对性能的提升的前提条件是同步块可以很快执行完成且系统是多核这样只需要忙等轮询很小一段时间就可以获取锁避免线程阻塞导致的开销。在代码即将进入同步块的时候如果此同步对象没有被锁定锁标志位为“01”状态虚拟机首先将在当前线程的栈帧中建立一个名为锁记录Lock Record的空间用于存储锁对象目前的Mark Word的拷贝官方为这份拷贝加了一个Displaced前缀即Displaced Mark Word。虚拟机将使用CAS操作尝试把对象的Mark Word更新为指向Lock Record的指针。如果这个更新动作成功了即代表该线程拥有了这个对象的锁并且对象Mark Word的锁标志位Mark Word的最后两个比特将转变为“00”表示此对象处于轻量级锁定状态。如果这个更新操作失败了那就意味着至少存在一条线程与当前线程竞争获取该对象的锁。虚拟机首先会检查对象的Mark Word是否指向当前线程的栈帧如果是说明当前线程已经拥有了这个对象的锁那直接进入同步块继续执行就可以了否则就说明这个锁对象已经被其他线程抢占了空转轮询一段时间锁要膨胀为重量级锁锁标志的状态值变为“10”跳转到7。重量级锁此时Mark Word中存储的就是指向重量级锁互斥量的指针后面等待锁的线程也必须进入阻塞状态。锁膨胀到重量级锁后可能导致线程阻塞而线程阻塞时需要通过操作系统指令完成的这种系统调用会导致程序用户态内核态的切换消耗系统资源。偏向锁、轻量级锁的状态转化及对象Mark Word的关系如下所示。锁的整体膨胀过程如下图所示偏向锁、轻量级、重量级锁优缺点分析finalfinal的安全承诺final对象只在初始化构建时进行赋值实例化成功后不允许改变其值从根本上避免了并发写入带来的线程安全问题。读一个对象的final域之前一定会先这个对象的引用如果引入对象不为null则final域一定被初始化了怎么做到的JMM禁止编译器把final域的写重排序到构造函数之外实现方法是在final域写之后构造函数return前插入一个StoreStore屏障。读对象final域之前插入LoadLoad屏障保证读对象final域之前一定会先读对象本身。3.JUC并发防范机制ReentrantLockRetrantLock提供了比synchronized更强大的功能更好的灵活性。它可以响应中断、支持超时时间设置、支持公平和非公平策略。lock.tryLock(5, TimeUtil.SECONDS); lock.lockInterruptibly();ReadWriteLock读写锁可以有效减少读写并发时的锁竞争进而减少线程阻塞提高响应时间。ConditionCondition用于协调多线程的复杂协作常与Lock配合使用通过lock.newCondition()可以生成与Lock绑定的Condition实例。Semaphore信号量为多线程协作提供了更加强大的控制方法。信号量是对锁的扩展无论是内部锁synchronized还是重入锁ReentrantLock一次仅允许一个线程访问资源而信号量则可以指定多个线程同时访问资源。构造方法如下public Semaphore(int permits) {} public Semaphore(int permits, boolean fair) {}主要方法public void acquire() throws InterruptedException {} public void acquireUninterruptibly() {} public boolean tryAcquire() {} public boolean tryAcquire(long timeout, TimeUtil unit) throews InterruptedException {} public void release() {}CountDownLatchCountDownLatch允许一个或多个线程等待其他线程完成操作。一个线程调用countDown方法happen-before另外一个线程调用await方法。API如下CountDownLatch latch new CountDownLath(2); latch.countDown(); latch.await();CyclicBarrier循环屏障可以做的事是让一组线程到达一个屏障也叫同步点时被阻塞直到最后一个现线程到达屏障才会打开。CyclicBarrier可用于多线程计算数据最后合并计算结果的场景。CyclicBarrier API如下CyclicBarrier barrier new CyclicBarrier(4, this); barrier.await(); ThreadLocalThreadLocal提供的并发防范机制有别于以上在数据共享常见下通过加锁来达到并发控制防范线程非安全情况出现即保证线程安全。ThreadLocal为每个线程提供变量的独立副本从而从根本上杜绝了数据共享线程之间根本就不会相互干扰也就不会有线程安全问题。4.线程安全集合ConcurrentHashMap是线程安全且高效的HashMap。BlockingQueue常用语生产者消费者场景、是线程安全的Queue。线程安全集合并不在本次讨论范围。总结本文较全面的讨论了Java并发控制机制在JVM层面通过volatile保证了内存的可见性和volatile写/读的先行发生关系。通过synchronized保证了多线程并发时对临界区的互斥访问以及锁的释放先行发生于锁的获取内存语义为了提供并发性能本文重点分析了内部锁的膨胀过程。通过final关键字保证了构造函数的调用先行发生于final域的读取并保证了final域的不可变性。除了JVM层面通过JMM定义的先行发生顺序外JUC也提供了并发防范工具包括RetrantLock、ReentrantReadWriteLock、Condition、Semaphore、CountDownLatch、CyclicBarrier以及ThreadLocal。
http://www.zqtcl.cn/news/841371/

相关文章:

  • 张家口网站建设vewanseo实战技术培训
  • 机加工网站室内设计联盟论坛
  • 汕头装修接单网站wordpress php加密
  • 重庆网站建设推广设置wordpress静态主页
  • 科技设计公司网站模板下载网站建设计划 文库
  • 建设美食网站做的好的阅读类的网站有哪些
  • 全屏网站模板制作教程吴江建设局房产网站
  • 浠水网站建设漳州找人做网站要求哪些
  • 做网站需要前台和后台吗公众号制作要求
  • 做一个网站 如何盈利模式招聘网站排行榜2021
  • 免费做网站网站有人哪些c 网站开发网易云课堂百度云下载
  • 高端品牌网站设计欣赏扬中网站建设包括哪些
  • 手机怎么访问微网站网络运营商电话
  • 怎么成立网站战争局势最新消息
  • 嘉定网站设计制作报价crm系统营销
  • 一个网站做几个关键词怎么样子做网站
  • 关于做网站的创新创业策划书怎么进网站后台管理系统
  • 品牌型网站开发wap网站开发工具
  • 网站改版设计微信淘宝购物券网站是怎么做的
  • 网站建设基本流程心得网站设计开发报价
  • 泉州网站建设网站制作电商网站建设需要
  • 沈阳工程建设信息网深圳seo网站排名优化
  • wordpress仿dz长沙seo网站优化
  • 西宁做网站公司电话关键词快速排名怎么做
  • 昆山网站建设秦皇岛淘宝关键词推广
  • 建设娱乐网站的要求微网站开发多少钱
  • 海港区网站快排seo网站怎么添加流量
  • 肇庆做网站aspaccess做网站
  • 郑州网站建设索q479185700wordpress输出用户中心链接
  • 网站重要三要素网站建设 找vx cp5173