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

国外网站网址创建网页费用

国外网站网址,创建网页费用,南通公司网站模板建站,东莞排名推广1、锁的可重入 一个不可重入的锁#xff0c;抢占该锁的方法递归调用自己#xff0c;或者两个持有该锁的方法之间发生调用#xff0c;都会发生死锁。以之前实现的显式独占锁为例#xff0c;在递归调用时会发生死锁#xff1a; public class MyLock implements Lock {/* 仅…1、锁的可重入 一个不可重入的锁抢占该锁的方法递归调用自己或者两个持有该锁的方法之间发生调用都会发生死锁。以之前实现的显式独占锁为例在递归调用时会发生死锁 public class MyLock implements Lock {/* 仅需要将操作代理到Sync上即可*/private final Sync sync new Sync();private final static class Sync extends AbstractQueuedSynchronizer {// 判断处于独占状态Overrideprotected boolean isHeldExclusively() {return getState() 1;}// 获得锁Overrideprotected boolean tryAcquire(int i) {if (compareAndSetState(0, 1)) {// 设置占有独占锁的线程setExclusiveOwnerThread(Thread.currentThread());return true;}return false;}// 释放锁Overrideprotected boolean tryRelease(int i) {if (getState() 0) {throw new IllegalMonitorStateException();}setExclusiveOwnerThread(null);setState(0);return true;}// 返回一个Condition每个condition都包含了一个condition队列public Condition newCondition() {return new ConditionObject();}}Overridepublic void lock() {System.out.println(Thread.currentThread().getName() ready get lock);sync.acquire(1);System.out.println(Thread.currentThread().getName() already got lock);}Overridepublic void lockInterruptibly() throws InterruptedException {sync.acquireInterruptibly(1);}Overridepublic boolean tryLock() {return sync.tryAcquire(1);}Overridepublic boolean tryLock(long timeout, TimeUnit timeUnit) throws InterruptedException {return sync.tryAcquireNanos(1, timeUnit.toNanos(timeout));}Overridepublic void unlock() {System.out.println(Thread.currentThread().getName() ready release lock);sync.release(1);System.out.println(Thread.currentThread().getName() already released lock);}Overridepublic Condition newCondition() {return sync.newCondition();} }测试代码 public class Test {private static MyLock lock new MyLock();private static class TestThread implements Runnable {public TestThread() {}Overridepublic void run() {System.out.println(Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}reenter(3);}public void reenter(int level) {lock.lock();try {System.out.println(Thread.currentThread().getName() :递归层级: level);if (level 0) return;reenter(level - 1);} finally {lock.unlock();}}}public static void main(String[] args) {for (int i 0; i 3; i) {Thread thread new Thread(new TestThread(new JavaBean(0)));thread.start();}} }输出结果 Thread-2 ready get lock Thread-0 ready get lock Thread-2 already got lock Thread-1 ready get lock Thread-2:递归层级:3 Thread-2 ready get lock代码停在这里发生死锁原因是 Thread-2 已经拿到了锁在递归到下一层时还要获取 lock但是 MyLock 没实现可重入使得它在执行 tryAcquire() 的原子操作 compareAndSetState(0,1) 时一直不成功因为期望值此时已经由 0 变成了 1。所以这里需要实现可重入锁。 想要实现可重入的锁需要让 state 作为锁的计数器 // 获得锁Overrideprotected boolean tryAcquire(int i) {if (compareAndSetState(0, 1)) {setExclusiveOwnerThread(Thread.currentThread());return true;} else if (getExclusiveOwnerThread() Thread.currentThread()) {setState(getState() 1);return true;}return false;}// 释放锁Overrideprotected boolean tryRelease(int i) {if (getExclusiveOwnerThread() ! Thread.currentThread()) {throw new IllegalMonitorStateException();}if (getState() 0) {throw new IllegalMonitorStateException();}setState(getState() - 1);if (getState() 0) {setExclusiveOwnerThread(null);}return true;}state 作为持有这个锁的线程的数量锁被持有了几次就要相应的释放几次。 2、Java 内存模型JMM 上图中工作内存和主内存是两个抽象的概念不是真实存在的实体它们可以是 CPU 寄存器、CPU 中的高速缓存甚至是主内存 RAM 的一部分。 线程在执行计算工作时会把需要用到的变量从主内存拷贝到自己的工作内存中。线程不能直接操作主内存中的数据也不能访问其它线程工作内存。这样的内存模型使得线程执行过程中面临两个问题可见性与原子性。 2.1 可见性与原子性 可见性是指当多个线程访问同一个变量时一个线程修改了这个变量的值其他线程能够立即看得到修改的值。 线程对变量的所有操作都必须在工作内存中进行不能直接读写主内存中的变量。对于共享变量 V多个线程先是在自己的工作内存之后再同步到主内存。但同步动作并不会及时的刷到主存中而是会有一定时间差。这个时候线程 A 对变量 V 的操作对于线程 B 而言就不具备可见性了。 要解决共享对象可见性这个问题可以使 用volatile 关键字或者是加锁。 原子性即一个操作或者多个操作要么全部执行并且执行的过程不会被任何因素打断要么就都不执行。 CPU 资源的分配都是以线程为单位的。任务切换大多数是在时间片段结束以后当然也可以在任何一条 CPU 指令执行完之后是 CPU 指令而不是某种高级语言的一个语句如 Java 中的 count 至少需要三条 CPU 指令才能完成这也可能导致线程安全问题。 举个例子假如两个线程都执行语句 count count 1如图所示 线程 A、B 都把 count 的初值 0 从主内存拷贝到自己的工作内存中开始执行 count 1 的操作都得到结果 1 再把副本值同步到主内存中。明明进行了两次计算但是得到的却是计算了一次的结果这是因为两个线程对于 count 的操作是互不可见的彼此不知道对 count 的操作。 上述问题发生的原因是未能保证线程操作的可见性可以使用 volatile 关键字或者是加锁解决可见性问题。 但是使用 volatile 修饰 count 后问题仍没有解决原因就是 count count 1 并不是一个原子操作完全有可能在执行完 count 1 之后赋值给 count 之前CPU 进行上下文切换到其它线程执行完整个 count count 1 并将结果同步回内存最后切换会原线程继续执行的情况这就是原子性问题。 2.2 volatile 关键字 volatile 是 Java 并发编程包中最轻量级的一个同步工具。 使用 volatile 关键字修饰一个变量会强迫线程每次在计算该变量之前从主内存中拿最新的变量值并且要求计算完成后立即将新的变量值同步到主内存中。 可以把对 volatile 变量的单个读/写看成是使用同一个锁对这些单个读/写操作做了同步。如 public class Volatile {volatile int i;// 单个 volatile 变量的读public int getI() {return i;}// 单个 volatile 变量的写public void setI(int i) {this.i i;}private void inc() {// Non-atomic operation on volatile field ii; // 复合多个volatile 变量的读/写} }等价于 public class Volatile {int i;// 单个 volatile 变量的读public synchronized int getI() {return i;}// 单个 volatile 变量的写public synchronized void setI(int i) {this.i i;}private void inc() {// 调用同步读int temp getI(); // 普通写可能在执行这一步之前发生线程切换导致 volatile 修饰的变量发生线程安全问题temp temp 1;// 调用同步写setI(temp);} }可见 volatile 只能保证对变量的单个操作的线程安全但像 i 这种复合操作volatile 则不能保证其线程安全。 因此 volatile 变量自身具有以下特性 可见性对一个 volatile 变量的读总是能看到任意线程对这个 volatile 变量最后的写入。原子性对任意单个 volatile 变量的读/写具有原子性但类似于 i 这种复合操作不具有原子性。 volatile 适用的场景有 一个线程写多个线程读。写线程能立即将结果写回内存而读线程能拿到变量在内存中最新的值。否则写线程的结果可能并不是立即写回内存的导致读线程拿到的变量不是最新多个线程写但是各个线程写的值没有关联count 5 这种直接赋值是没有关联的但是像 count count 1 这种基于 count 原始值的认为是有关联。 volatile 还有一个功能就是抑制重排序。 重排序是指在现代 CPU 中同一时刻可以执行多条指令可能会造成实际执行的代码顺序与编写的顺序不同的情况。例如 do(...) {int a 5; // 1int b 10; // 2int t;if (b 5) {t b;}}指令重排后可能后编写的语句会先被执行即便 b 5 的条件还未满足也先执行 t b只不过对于这种条件语句可能会先存入重排序缓冲区中等到 b 5 满足时再从缓冲中取出执行。重排序在单线程中是不会出现乱序问题的但是多线程则可能会出现。如果用 volatile 修饰某个变量就不会对其进行重排序。 Intel CPU 可以有十级流水线即 CPU 可以在同一时刻执行十条指令Android 芯片的 ARM 架构也可达到三级流水线。 volatile 的实现原理是被 volatile 修饰的共享变量进行读写操作的时候会使用 CPU 提供的 Lock 前缀指令。该指令的作用是 将当前处理器缓存行的数据写回到系统内存。写回内存的操作会使其它 CPU 里缓存了该内存地址的数据无效。 以上是对 volatile 关键字的介绍。最后我们再回头看下 count count 1 的问题的解决方案 使用 volatile 关键字搭配 CAS 操作前者保证可见性后者保证原子性。实际上 JDK 中很多同步操作都是使用 volatile CAS 来代替 synchronized。直接用锁synchronized、Lock… 3、synchronized 实现原理 3.1 monitorenter 和 monitorexit 指令 底层是使用 monitorenter 和 monitorexit 指令实现的。对于使用了 synchronized 同步代码块的代码 public class IncTest {private int count;// public 才能被 javap 反编译出来public int inc() {synchronized (this) {return count;}} }编译后使用 javap -v IncTest.class 命令反编译会看到 inc 方法的汇编指令 真正执行 count 操作的指令是在第4行~第15行而第3行的 monitorenter 与第16行的 monitorexit 则分别是获取锁和释放锁的指令。这两条指令是由编译器插入的。而使用同步方法时 public class IncTest {private int count;// public 才能被 javap 反编译出来public synchronized int inc() {return count;} }其汇编指令为 同步方法的汇编指令没有显式的 monitorenter 和 monitorexit 指令但是在方法的 flags 上能看到多出了一个 ACC_SYNCHRONIZED在运行时还是用到了 monitorenter 和 monitorexit 指令只不过无法在字节码指令上体现出来。 总结一下 monitorenter 指令是在编译后插入到同步代码块的开始位置而 monitorexit 是插入到方法结束处和异常处。每个 monitorenter 必须有对应的 monitorexit 与之配对。任何对象都有一个 monitor 与之关联。 3.2 锁的存放位置与锁升级 Java 对象在内存中由三部分组成对象头、实例数据和对齐填充字节。synchronized 锁就存放在对象头中它由三部分组成Mark Word、指向类的指针也称 KlassPoint和数组长度只有数组对象才有 它们的长度与虚拟机位数保持一致以 32 位为例Mark Word 的存储内容是这样的 分代年龄是指对象经历过 GC 的次数。堆内存至少会被划分成两部分一部分存放新生代对象一部分存放老年代对象。JVM 默认一个新生代对象经历过15次 GC 还没有被回收就认为该对象是一个需要长期储存的对象于是就把它移入堆内存的老年代存放区。 我们都知道 synchronized 同步锁是一个重量级的锁拿锁失败的线程会发生上下文切换被阻塞直到拿到锁后又发生上下文切换由阻塞状态变成运行状态。因为上下文切换的耗时相对于 CPU 执行指令的时间是非常耗时的一次上下文切换需要大概5000~20000个单位时间在3~5毫秒左右而一个1.6G的 CPU 执行一条指令耗时0.6纳秒对于一个100条指令的任务CPU 的执行时间也就仅仅在0.6毫秒左右。因此如果使用 synchronized 执行一个较轻量级的任务被阻塞等待的时间远远超过了执行任务本身所需的时间。 为了对上述情况做出优化从 JDK 1.6 开始出现了锁升级的概念意思是说一个 synchronized 锁在 Mark Word 中的状态不是一成不变的会根据任务的量级对锁的量级逐步提升即无锁状态-偏向锁状态-轻量级锁状态-重量级锁状态锁的四种状态 3.2.1 偏向锁 大多数情况下锁不仅不存在多线程竞争而且总是由同一线程多次获得统计发现为了让线程获得锁的代价更低而引入了偏向锁锁总是会倾向于分配给第一次拿到这个锁的线程。无竞争时不需要进行 CAS 操作来加锁和解锁而是直接把锁给到当前线程。但是一旦发生多个线程间的资源竞争就要把偏向锁升级为轻量级锁在升级之前要先撤销偏向锁。 偏向锁撤销时中有一个 Stop the World 现象。Stop the World 是指 在新生代进行的GC叫做minor GC在老年代进行的GC都叫major GCFull GC同时作用于新生代和老年代。在垃圾回收过程中经常涉及到对对象的挪动比如上文提到的对象在Survivor 0和Survivor 1之间的复制进而导致需要对对象引用进行更新。为了保证引用更新的正确性Java将暂停所有其他的线程这种情况被称为“Stop-The-World”导致系统全局停顿。Stop-The-World对系统性能存在影响因此垃圾回收的一个原则是尽量减少“Stop-The-World”的时间。 引用自 JVM学习7Stop-The-World 看上图线程2在撤销线程1的偏向锁时需要修改线程1工作内存中的相关数据在修改之前要停止线程1的执行否则线程2无法修改。因此这里也是发生了 Stop the World 现象由于它会停止其它线程因此在有多个线程竞争资源时是不推荐使用偏向锁的。 3.2.2 轻量级锁 轻量级锁通过 CAS 操作来加锁和解锁。其中的自旋锁借鉴了 CAS 的思想不会阻塞没有拿到锁的线程而是让其自旋。假如获取到锁的那个线程执行速度很快那么自旋中的线程也可能很快就拿到了锁这样能节省出两次上下文切换的时间。 但是自旋是占用 CPU 在不停的循环执行检测的倘若线程任务中有访问服务器之类的重量级操作如果还是一直不停的自旋就使得 CPU 不能充分的利用。因此又产生了适应性自旋锁它会根据算法决定自旋的时间/次数一般这个时间就是一次上下文切换的时间。因为引入轻量级锁的目的就是通过自旋节省掉使用重量级锁时产生的上下文切换的时间如果自旋时间已经超过上下文切换时间那么自旋也就没有意义了此时就要把轻量级锁膨胀为重量级锁。 锁只能升级不能降级。
http://www.zqtcl.cn/news/520297/

相关文章:

  • 网站建设容易出现的问题网站建设学习网公司有哪些
  • 做网站的准备什么com域名
  • 百度资料怎么做网站赣州有没有做网站的
  • 网站上地图怎么做的福建省晋江市建设局网站
  • 休闲咖啡厅网站开发目标站内推广的方法和工具
  • 东莞做营销型网站怎样利用网站做引流
  • 国际1688网站网络平台宣传费用
  • 免费网站自助建站18款禁游戏黄app入口
  • 网站建设要经历哪些步骤?wordpress主题king
  • 个人定制网站外贸免费网站建设
  • ASP网站建设实训报告总结宜昌本地网站建设
  • 甘肃省建设厅官方网站张睿建立网站服务器
  • 有没有做博物馆的3d网站网页美工设计岗前培训
  • 如何防止网站被盗长沙知名网站建设
  • 汕尾住房和建设局网站山西招标网
  • 网站建设那好山西建设厅网站
  • 2免费做网站外贸公司注册需要多少钱
  • 莘县网站定制安卓软件开发培训机构
  • 织梦视频网站源码有没有专门做名片的网站
  • 济南本地网站自己做的网站怎么置顶
  • wordpress能做多大的站好用的网站后台
  • 想自己做网站流程国家住建网查企业资质
  • 英文网站怎么设计google浏览器入口
  • 重庆网站建设公司魁网个人备案网站名
  • 怀柔营销型网站建设wordpress菜单定制
  • 大连装修网站推广天津市建设信息工程网
  • 服装网站建设建议域名注册最好的网站
  • 小游戏网站网络营销推广岗位
  • 做一百度网站保健品网站建设案例
  • 沙田镇仿做网站如何建设钓鱼网站