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

做印刷厂网站苏州工业园区服务外包职业学院

做印刷厂网站,苏州工业园区服务外包职业学院,成都的网站建设公司,海口海南网站建设一、概述 线程安全在并发编程中是重要关注点#xff0c;造成线程安全问题的主要诱因有两个#xff1a;一是存在共享数据#xff08;也称临界资源#xff09;#xff0c;二是存在多个线程共同操作共享数据。synchronized关键字能够保证在同一时刻只有一个线程可以执行某个…一、概述 线程安全在并发编程中是重要关注点造成线程安全问题的主要诱因有两个一是存在共享数据也称临界资源二是存在多个线程共同操作共享数据。synchronized关键字能够保证在同一时刻只有一个线程可以执行某个方法或某个代码块。 1、synchronized作用 原子性synchronized保证语句块内操作是原子的 可见性synchronized保证可见性通过“在执行unlock之前必须先把此变量同步回主内存”实现 有序性synchronized保证有序性通过“一个变量在同一时刻只允许一条线程对其进行lock操作” 2、synchronized使用 修饰实例方法作用于当前实例加锁进入同步代码前要获得当前实例的锁修饰静态方法作用于当前类对象加锁进入同步代码前要获得当前类对象的锁修饰代码块指定加锁对象对给定对象加锁进入同步代码库前要获得给定对象的锁。 二、实现原理 synchronized在Java中实现原理主要是基于Java的内存模型JMM和对象锁机制。 1、Java内存模型JMM 依赖于JMM对一个变量unlock之前必须要同步到主内存对变量进行lock操作将会清空本地内存中此变量的值从新从主内存中load或assign初始化变量值。JMM定义了线程与主内存之间的抽象关系 1. 线程之间的共享变量存储在主内存中。 2. 每个线程都有一个私有的本地内存也称为工作内存本地内存中存储了该线程使用到的主内存副本的拷贝 3. 线程对变量的所有操作读取、赋值等都必须在自己的本地内存中进行而不能直接读写主内存中的变量 多线程在JMM内存模型中运行机制 2、对象锁机制 synchronized通过对象锁机制来保证同一时刻只有一个线程可以访问被锁定的代码块或方法。在JVM中synchronized的实现都是基于进入和退出Monitor对象来实现方法同步和代码块同步的。所以谈synchronized的实现需要先说下对象在JVM中的存储Java对象头、Monitor对象监听器。 2.1 对象结构 在HotSpot虚拟机中对象在堆内存存储的布局主要分为三个区域对象头、实例数据、填充数据。 实例数据存放类的属性数据信息包括父类的属性信息。若是数组的实例部分还包括数组的长度。这部分内存按4字节对齐。 填充数据由于虚拟机要求对象的起始地址必须是8字节的整数倍。填充数据不是必须存在的。 对象头对象头包括了分为两部分信息第一部分存储对象自身运行时数据如哈希码、GC分代年龄、锁状态等信息被称为MarkWord。另一部分用于存储执行对象类型数据的指针被称为ClassPoint。若是数组对象还会有一个额外部分存储数组长度。 2.2 对象头组成 对象头包括了MarkWord和ClassPoint两部分若是数据对象还有一个额外部分存储数组长度。 MarkWord MarkWord主要用来存储对象自身运行时的数据信息如hashCode、GC分代年龄等。MarkWord的位长度为JVM的一个Word大小32位JVM的MarkWord是32位64位JVM的MarkWord是64位。 其中各部的含义如下 锁标志位lock用低两位表示锁标志位该标记位的数据不同代表MarkWord的含义不同。 偏向锁位1bit锁标记位2bit锁状态001无锁状态101偏向锁000轻量级锁010重量级锁011GC标记信息 偏向锁位bias_lock对象是否启动偏向锁标记只占1个二进制位。为1时表示对象启动偏向锁为0时表示对象没有偏向锁。 分代年龄age4位的Java对象年龄。在GC中如果对象在Survivor区复制一次年龄增加1。当对象达到设定的阈值时将会晋升到老年代。默认情况下并行GC的年龄阈值为15并发GC的年龄阈值为6。由于age只有4位所以最大值为15这就是-XX:MaxTenuringThreshold选项最大值为15的原因。 hashCode31位的对象标识Hash码采用延迟加载技术。调用方法System.identityHashCode()计算并会将结果写到该对象头中。当对象被锁定时该值会移动到管程Monitor中。 JavaThread持有偏向锁的线程ID。 Epoch偏向时间戳。 lock recordptr_to_lock_record指向栈中锁记录的指针。 互斥量ptr_to_heavyweight_monitor指向monitor对象也称为管程或监视器锁的起始地址每个对象都存在着一个monitor与之关联对象与其monitor之间的关系有存在多种实现方式如monitor对象可以与对象一起创建销毁或当前线程试图获取对象锁时自动生但当一个monitor被某个线程持有后它便处于锁定状态。 ClassPoint 这一部分用于存储对象的类型指针该指针指向它的类元数据JVM通过这个指针确定对象是哪个类的实例。该指针的位长度为JVM的一个字大小即32位的JVM为32位64位的JVM为64位。 如果应用的对象过多使用64位的指针将浪费大量内存统计而言64位的JVM将会比32位的JVM多耗费50%的内存。为了节约内存可以使用选项UseCompressedOops开启指针压缩其中oop即ordinary object pointer普通对象指针。开启该选项后下列指针将压缩至32位 每个Class的属性指针即静态变量每个对象的属性指针即对象变量普通对象数组的每个元素指针 当然也不是所有的指针都会压缩一些特殊类型的指针JVM不会优化比如指向PermGen的Class对象指针(JDK8中指向元空间的Class对象指针)、本地变量、堆栈元素、入参、返回值和NULL指针等 2.3 Monitor监视器锁 Monitor介绍 在Java虚拟机HotSpot中monitor是由ObjectMonitor实现的其主要数据结构如下位于HotSpot虚拟机源码ObjectMonitor.hpp文件C实现的 ObjectMonitor中有两个队列_WaitSet 和 _EntryList用来保存ObjectWaiter对象列表( 每个等待锁的线程都会被封装成ObjectWaiter对象)_owner指向持有ObjectMonitor对象的线程。 当多个线程同时访问一段同步代码时首先会进入 _EntryList 集合当线程获取到对象的monitor 后进入 _Owner 区域并把monitor中的owner变量设置为当前线程同时monitor中的计数器count加1若线程调用 wait() 方法将释放当前持有的monitorowner变量恢复为nullcount自减1同时该线程进入 WaitSe t集合中等待被唤醒。若当前线程执行完毕也将释放monitor(锁)并复位变量的值以便其他线程进入获取monitor(锁)。执行过程如下 由此看来monitor对象存在于每个Java对象的对象头中(存储的指针的指向)synchronized锁便是通过这种方式获取锁的也是为什么Java中任意对象可以作为锁的原因同时也是notify/notifyAll/wait等方法存在于顶级对象Object中的原因。 对象Object的Monitor机制 Java虚拟机给每个对象和class字节码都设置了一个监听器Monitor用于检测并发代码的重入同时在Object类中还提供了notify和wait方法来对线程进行控制。 Object类中的代码如下 public class Object { … private transient int shadow$monitor; public final native void notify(); public final native void notifyAll(); public final native void wait() throws InterruptedException; public final void wait(long millis) throws InterruptedException { wait(millis, 0); } public final native void wait(long millis, int nanos) throws InterruptedException; … } Monitor可以类比为一个特殊的房间这个房间中有一些被保护的数据Monitor保证每次只能有一个线程能进入这个房间进行访问被保护的数据进入房间即为持有Monitor退出房间即为释放Monitor。 当一个线程需获取锁对象的Monitor时它会首先在entryList入口队列中排队若无线程正在持有锁对象的Monitor那么该线程会和entryList队列、waitSet队列中其他线程进行竞争即通过CPU调度选出一个线程来获取锁对象的Monitor执行受保护的方法或代码块。执行完毕后释放锁对象的Monitor。若已经有线程持有锁对象的Monitor那么需要等待其释放Monitor后再进行竞争。 waitSet队列当一个线程拥有Monitor后经过某些条件的判断比如用户取钱发现账户没钱这个时候需要调用Object的wait方法线程就释放了Monitor进入waitSet队列等待Object的notify方法比如用户向账户里面存钱。当该对象调用了notify方法或者notifyAll方法后waitSet中的线程就会被唤醒然后在waitSet队列中被唤醒的线程和entryList队列中的线程一起通过CPU调度来竞争对象的Monitor最终只有一个线程能获取对象的Monitor。 三、JDK1.6对synchronized的优化 synchronized是通过对象内部的一个叫做监视器锁monitor来实现的监视器锁本质又是依赖于底层的操作系统的Mutex Lock互斥锁来实现的。而操作系统实现线程之间的切换需要从用户态转换到核心态这个成本非常高。这种依赖于操作系统Mutex Lock所实现的锁我们称之为“重量级锁”。JDK团队在JDK1.6中对synchronized进行了大量优化主要包括锁消除、锁膨胀、锁升级三部分。 1、锁消除 当JVM在JITJust-In-Time编译时在Synchronized修饰的代码中的锁不可能被其他线程访问到即不存在操作临界资源竞争情况那么JVM在编译时会将这个锁清除。这样可以避免无谓的锁操作提升执行效率。即便写了Synchronized也不会触发。 2、锁膨胀 在JDK1.6中引入了锁膨胀的优化技术。当JVM检测到一段代码中有多次加锁和解锁的操作时若这些锁针对同一个对象并且加锁和解锁操作频繁但加锁范围小JVM会将锁的范围扩展到更大区域从而减少锁的获取和释放次数降低锁的开销。 如在for循环中频繁的获取和释放锁资源这样带来的消耗很大通过锁膨胀将锁范围扩大减少资源消耗。代码如下 public void method(){for(int i 0; i 999999; i){synchronized(对象){}}}JVM对上面代码编译时会触达锁膨胀编译后代码 public void method(){synchronized(对象){for(int i 0; i 999999; i){}} } 3、锁升级 ReentrantLock的实现是先基于乐观锁的CAS尝试获取锁资源若拿不到资源才会挂起线程。在JDK1.6中synchronized引入了无锁、偏向锁、轻量级锁和重量级锁等多种锁状态。锁的升级是 为了提高获取锁和释放锁的效率但升级后的锁会带来更好的性能开销。锁升级是单向的从偏量锁开始根据竞争程度逐步升级为轻量级锁和重量级锁。 3.1 无锁 当一个线程访问一个没有被锁定的代码块时这个代码块处于无锁状态。此时任何线程都可以访问这个代码块不需要进行任何锁的竞争。 3.2 偏向锁 偏向锁的目的是共享数据在无竞争的情况下提高获取锁的性能。 获取偏向锁 1. 判断锁对象的锁状态否为“101”-可偏向状态 2. 若为可偏向状态则判断锁对象头中的线程ID是否是当前线程若是进入同步块 3. 若线程ID并未指向当前线程会基于CAS方式尝试将偏向锁指向当前线程。若操作成功将Mark Word中线程ID更新为当前线程ID进入同步块 4. 若操作失败代表出现了锁的竞争准备撤销偏向锁。会根据线程是否处于活动状态决定是转换为无锁状态还是升级为轻量级锁。 当一个线程第一次访问一个被synchronized锁保护的代码块时这个代码块会尝试进入“101”-偏向锁状态。此时JVM会将锁对象头中的标记位设为“偏向模式”并记录持有锁的线程ID。此后该线程再次访问这个代码块时可以直接获取锁不需要进行任何锁的竞争。偏向锁可以提高无竞争情况下的性能。 释放偏向锁 偏向锁使用了遇到竞争才释放锁的机制。偏向锁的撤销需要等待全局安全点然后它会首先暂停拥有偏向锁的线程然后判断线程是否还活着如果线程还活着则升级为轻量级锁否则将锁设置为无锁状态。 3.3 轻量级锁 轻量级锁也是JDK1.6引入的新型锁机制。它不是用来替换重量级锁的它的本意是在没有多线程竞争的情况下减少传统的重量级锁使用操作系统互斥量产生的性能消耗。 轻量级锁是一种基于CAS自适应自旋锁的方式尝试获取锁资源。使用CAS尝试将线程ID存储到锁对象的对象头中。若操作成功则表示当前线程成功获取锁。若操作失败则表示锁已被其他线程持有当前线程需要等待或其他同步操作。 获取轻量级锁 1. 当线程尝试进入同步代码或方式时JVM会检查锁对象的状态。JVM首先在当前线程的栈帧中建立一个名为锁记录Lock Record的空间用于存储锁对象目前Mark Word的拷贝。 2. 若锁对象的Mark Word表明锁处于无锁状态即未被任何线程持有JVM会尝试将锁膨胀为轻量级锁。膨胀过程中JVM会将锁对象的Mark Word更新为指向当前线程的栈帧中的锁记录Lock Record的指针。 3. 为确保轻量级锁获取是原子的JVM会利用CAS自适应自旋锁方式尝试将锁对象的Mark Word更新为指向当前线程的锁记录。 4. 若更新成功那么该线程就拥有了该对象的锁并且锁对象的Mark Word锁标志位转变为“00”即表示此对象处于轻量级锁定状态 5. 若更新失败JVM首先会检查锁对象的Mark Word是否指向当前线程的栈帧若锁对象被其他线程持有则当前线程会自旋等待在一定时间被循环尝试重新获取锁。 6. 若自旋次数超过预设的阈值或JVM检测到有多个两个以上线程在竞争同一个锁JVM会将锁升级为重量级锁。 自适应自旋锁是基于CAS操作实现线程如果自旋成功了那么下次自旋的次数会更加多反之会减少自旋次数甚至取消。 释放轻量级锁 如果锁对象的Mark Word仍然指向线程的锁记录那就用CAS操作将锁对象当前的Mark Word与线程栈帧中的Displaced Mark Word交换回来如果替换成功整个同步过程就完成了。如果替换失败说明有其他线程尝试过获取该锁那就要在释放锁的同时唤醒被挂起的线程。 3.4 重量级锁 Synchronized的重量级锁是通过对象内部的一个叫做监视器锁monitor来实现的监视器锁本质又是依赖于底层的操作系统的Mutex Lock互斥锁来实现的。而操作系统实现线程之间的切换需要从用户态转换到核心态这个成本非常高状态之间的转换需要相对比较长的时间这就是为什么Synchronized效率低的原因。 3.5 偏向锁、轻量级锁和重量级锁对比 1. 如果是单线程使用偏向锁的代价最小每次判断当前线程是否独占该锁即可 2. 如果出现了其他线程竞争则偏向锁就会升级为轻量级锁 3. 线程达到最大自旋次数升级为重量级锁 四、与ReentrantLock区别 1、底层实现 synchronized是JVM层面的锁通过对象头中的Mark Word来实现锁的获取和释放。底层是基于ObjectMonitor实现。它支持偏向锁、轻量级锁和重量级锁等多种锁状态以优化性能。 ReentrantLock是API层面的锁基于AbstractQueuedSynchronizerAQS框架实现。AQS是一个用于构建锁和其他同步类的框架提供了丰富的同步原语。 2、锁的获取和释放 synchronized隐式地获取和释放锁。当线程进入synchronized修饰的方法或代码块时会自动获取锁并在方法或代码块执行完毕后自动释放锁。 ReentrantLock显式地获取和释放锁。线程需要调用lock()方法来获取锁并在使用完毕后调用unlock()方法来释放锁也可以通过tryLock()方法尝试获取锁。这种显式的方式提供了更高的灵活性但也要求程序员必须确保在finally块中释放锁以避免死锁。 3、锁的公平性 synchronized非公平锁。synchronized无法保证等待时间最长的线程会最先获得锁。 ReentrantLock可以是公平锁也可以是非公平锁。通过构造函数中的布尔值参数可以指定锁的公平性。公平锁会按照线程请求锁的顺序来分配锁而非公平锁则允许插队。 4、锁的灵活性 synchronized是Java语言的关键字使用起来相对简单但灵活性较低。它无法设置超时时间也无法尝试获取锁而不阻塞当前线程。 ReentrantLock提供了更高的灵活性。可以设置超时时间或tryLock()方法尝试获取锁而不阻塞当前线程以及检查锁是否被某个线程持有等。 5、响应中断 synchronized无法响应中断。当线程在synchronized代码块中等待锁时如果线程被中断它会继续等待直到获取到锁然后才能抛出InterruptedException。 ReentrantLock可以响应中断。当线程在ReentrantLock的lock()或lockInterruptibly()方法中等待锁时如果线程被中断它会立即抛出InterruptedException并释放已经占有的锁如果是lockInterruptibly()。 6、锁的绑定条件 synchronized不支持绑定多个条件。synchronized只能用于控制对共享资源的访问而无法提供复杂的线程间通信机制。 ReentrantLock支持绑定多个Condition条件。ReentrantLock可以与多个Condition对象关联以实现更复杂的线程间通信和协作。
http://www.hkea.cn/news/14282618/

相关文章:

  • 湖南省网站备案泉州网站搭建
  • 南头英文网站建设网站后台更新栏目后 网站
  • 个人网站需求分析整站优化报价
  • 做58招聘网站工作人员的心得汕头app开发
  • 网站开发与规划就业前景门户网站开发费用
  • 沈阳城市建设管理学校网站做地理题的网站
  • iis配网站常宁市网站建设
  • 呼伦贝尔建设网站个人网页设计的主要内容和要求
  • 最棒的网站建设漫画网站源码
  • react 手机网站开发百度站长工具使用方法
  • 家具公司网站源码工程造价招聘网最新招聘
  • 有经验的江苏网站建设小程序开发 杭州
  • 长沙网站搭建首选智投未来如何与网站建立私密关系
  • 建设项目验收网站公示手机上如何制作自己的网站
  • 安徽住房和城乡建设厅新网站灰色 网站
  • 南阳网站推广优化公司审计网站建设毕业设计
  • 清远企业网站建设北京到广州列车时刻表
  • oa网站开发淘宝网络营销方案
  • 零基础网站建设教学在哪里贵金属交易平台
  • 做pc端网站多少钱广西排名前十的模板厂
  • 软件下载网站模板福永自适应网站建设
  • wordpress 物流主题做百度移动网站优化排
  • 怎么做网站转盘企业网络营销网站设计
  • vs 网站开发wordpress建公司官网
  • 买了域名之后如何做网站重庆网红景点洪崖洞已挤满游客
  • 平台网站可以做第三方检测报告个人介绍网站内容
  • 票据理财网站建设互联网公司排名2018
  • 手表常用网站wordpress 上传绕过
  • 网站开发建设技术规范书网站蜘蛛爬行统计
  • 为什么说新浪的门户网站做的好荷城网站制作公司