展开

关键词

Java面试题

spinlock重点:尝试获取的线程不会立即阻塞,而是采用循环的方式去尝试获取,这样的好处是减少线程上下文切换的消耗,不会堵塞。 this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }手敲:代码:package com.juc.lock; public class SpinLockDemo { ** * 原子引用线程 * AtomicReference atomicReference = new AtomicReference(); ** * 己写一个 + new Date()); 交换不成功则一直 while (! Tue May 05 20:03:00 CST 2020从结果可以看出,在线程1还没有释放时,线程2无法执行操作,仅仅是进入后不断循环直到线程1释放。这就是的妙处。

20620

图森未来面试官:Java并发中,如何实现同步?

关于我们知道是实现同步的一种方案,它是一种非阻塞。它与常规的主要区别就在于获取失败后的处理方式不同,常规会将线程阻塞并在适当时唤醒它。 而的核心机制就在两个字,即用操作来替代阻塞操作。某一线程尝试获取某个时,如果该已经被另一个线程占用的话,则此线程将不断循环检查该是否被释放,而不是让此线程挂起或睡眠。 这里将介绍4中常见的实现方案,包括最原始的、排队、CLH以及MCS。每种实现方式都有己的优缺点,下面我们详细看每种实现方案。 执行过程原始的缺点如下:它不具有公平性,不能保证先到的线程先获取,不管先来还是后到都得一起竞争。 排队鉴于原始存在公平性问题,于是引入一种排队机制来解决它,这就是排队

12440
  • 广告
    关闭

    云产品限时秒杀

    云服务器1核2G首年50元,还有多款热门云产品满足您的上云需求

  • 您找到你想要的搜索结果了吗?
    是的
    没有找到

    在这一篇中我们主要介绍第一种优化也就是 我们知道线程同步是用线程阻塞的方式来实现的。 这种的优化方式就是并不能代替线程的阻塞,它的目的是为了解决线程频繁的执行暂停和恢复也就是线程切换而存在的。如果其它线程占用的时间较短,那么的优化方式效果就会非常明显。 所以为了解决上述问题,一定有某种条件的限制,而不能让一直等待下去。所以在虚拟机中有规定,循环的次数默认是10次。 本质上只有一种,但虚拟机为了更好的优化于是在JDK 1.6中引入了适应的适应的意思就是循环的次数不是上述所说的默认10次了。而是根据上一个线程获取到时它的时间来决定的。 除此之外适应还会检测,如果发现对于某一个完成后很少成功的获得,那么在以后要获取这个时将尽可能的省略掉的过程,以避免浪费处理器的资源。

    48230

    :竞争的失败的线程,并不会真实的在操作系统层面挂起等待,而是JVM会让线程做 几个空循环(基于预测在不久的将来就能获得),在经过若干次循环后,如果可以获得,那么进入临界区,如果还不能获得,才会真实的将线程在操作系统层面进行挂起 适用场景:可以减少线程的阻塞,这对于竞争不激烈,且占用时间非常短的代码块 来说,有较大的性能提升,因为的消耗会小于线程阻塞挂起操作的消耗。 如果的竞争激烈,或者持有的线程需要长时间占用执行同步块,就不适合使用 了,因为在获取前一直都是占用cpu做无用功,线程的消耗大于线程阻塞挂起操作的消耗,造成cpu的浪费。

    24200

    的具体描述,可以看这里:https:blog.csdn.netzy010101articledetails83869140适合于被持有的时间比较短的场合,这样能避免线程调度的时候花费的成本 正如前面文章中所述,一般作为底层的PV原语来实现其它类型的在非抢占式调度中非常有用。 1.提供互斥机制2.阻塞中断阻塞中断,在非抢占式调度非常重要,中断处理程序不会使系统陷入死状态,因为它需要获取已被加。在这种内核中,中断处理程序是不能休眠的,因为它只使用。 (不抢占,只能等待时间片用完,或者是)在用户层面而言,不被经常使用。APUE中这样写到,从他的描述不难看出,不希望在用户层面使用。 试图对没有加进行解,结果是未定义的;如果当前线程已经获取了并加,继续加的结果也是未定义的。这有可能引起永久

    14020

    偏向、轻量级、重量级适应

    状态下,当一个线程A尝试进入同步代码块,但是当前的已经被线程B占有时,线程A不进入阻塞状态,而是不停的空转,等待线程B释放。 优点:开启后能减少线程的阻塞,在对于的竞争不激烈且占用时间很短的代码块来说,能提升很大的性能,在这种情况下的消耗小于线程阻塞挂起的消耗。 适应适应意味着的时间不再固定了,而是由前一次在同一个上的时间及的拥有者的状态来决定:如果在同一个对象上,等待之前成功获得过的,并且持有的线程正在运行中,那么虚拟机就会认为这次也很有可能再次成功 相反的,如果对于某个很少成功获得过,那么以后要获取这个时将可能减少时间甚至省略过程,以避免浪费处理器资源。适应解决的是“竞争时间不确定”的问题。 因此,可以根据上一次的时间与结果调整下一次的时间。6. 总结 类型 优点 缺点 适用场景 偏向和解不需要额外的消耗,和执行非同步方法比仅存在纳秒级的差距。

    39510

    Java---偏向、轻量级、重量级

    synchronized会导致争用不到的线程进入阻塞状态,所以说它是java语言中一个重量级的同步操纵,被称为重量级,为了缓解上述性能问题,JVM从1.5开始,引入了轻量与偏向,默认启用了 了解了markword结构,有助于后面了解java的加过程;小结前面提到了java的4种,他们分别是重量级、轻量级和偏向,  不同的有不同特点,每种只有在其特定的场景下,才会有出色的表现 ,java中没有哪种能够在所有情况下都能有出色的效率,引入这么多的原因就是为了应对不同的情况;前面讲到了重量级是悲观的一种,、轻量级与偏向属于乐观,所以现在你就能够大致理解了他们的适用范围 ,但是具体如何使用这几种呢,就要看后面的具体分析他们的特性;java中的原理非常简单,如果持有的线程能在很短时间内释放资源,那么那些等待竞争的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态 所以这种情况下我们要关闭时间阈值的目的是为了占着CPU的资源不释放,等到获取到立即进行处理。但是如何去选择的执行时间呢?

    45330

    Windows 驱动开发 - ,队列,链表的使用.

    目录windows 驱动开发之结构的使用一丶1.1 简介1.2 使用1.3 错误的用法二丶 链表中使用2.1 简介三丶队列3.1 简介windows 驱动开发之结构的使用一丶 其实就是用来限制多线程对同一数据资源的访问而设定的。 而内核中的与Ring3层的临界区类似。看看如何使用吧。 1.2 使用初始化是内核中提供的一种高IRQL的,用同步以独占的方式来访问某个资源。 我们定义一个并且传入进去,他就会给我们进行初始化。那么以后就是用这个值即可。 使用 使用分别使用以下两个函数即可。 所以在使用队列的时候一定注意不要和混用。比如等待使用 , 释放使用队列

    8810

    spin_lock

    的引入原子变量适用在多核之间多单一共享变量进行互斥访问,如果要保护多个变量,并且这些变量之间有逻辑关系时,原子变量就不适用了。例如:常见的双向链表。假设有三个链表节点A、B、C。 如果是0说明可以获得;如果不为0,说明处于上状态,不能访问,执行bne 1b指令,跳到标号1处不停执行。 strexeq %0, %2, lock->lock=1 使用常量1来更新的状态,并将执行结果放入到tmp中 teqeq %0, #0 if(tmp == 0) 用来判断tmp是否为0,如果为0,表明更新的状态成功 ;如果不为0表明的状态没哟更新成功,执行”bne 1b”,跳转到标号1继续执行。 将这个现象转移到程序中就是,在现代多核的cpu中,因为每个cpu都有chach的存在,导致不需要去访问主存获取lock,所以当当前获取lock的cpu,释放后,使其他cpu的cache都失效,然后释放的在下一次就比较容易进入临界去

    27851

    Java并发之高级CLH和MCS

    (spin lock)是一个典型的对临界资源的互斥手段,是基于CAS原语的,所以它是轻量级的同步操作,它的名称来源于它的特性。 (4)乱序执行(4)分枝技术(4)控制器的分类及特点关于的种类大体上有四种:(1)简单(非公平)不能保证公平性(2)基于票据的(公平)虽然解决了公平性的问题,但是多处理器系统上, myNode,L个有L个tail),CLH的一种变体被应用在了JAVA并发框架中。 CLH在SMP系统结构下该法是非常有效的。 实现CLH和MCS关于简单的和基于票号的前面的文章已经介绍过,这里不再重复介绍。 是Java并发包的基石之一,而CLH的原理和思想则是AbstractQueuedSynchronizer的基石之一,JDK里面的CLH的是增强改进后的CLH

    1.5K30

    Java并发编程:AQS的

    与互斥类似,保证了公共数据在任意时刻最多只能由一条线程获取使用,不同的是在获取失败后会采取的处理方式。? 01 是一种非阻塞,它的核心机制就在两个字,即用操作来替代阻塞操作。 03 特点的核心机制就是死等,所有想要获得的线程都在不停尝试去获取,当然这也会引来竞争问题。与互斥一样,也只允许一个线程获得适用于持有时间叫短的场景,即保护临界区很小的常见,这个很容易理解,如果持有太久,那么将可能导致大量线程都在,浪费大量CPU资源。 05 AQS的机制AQS框架中不管是互斥还是共享实现的基础思想都是基于的机制,不过它对做了优化,这个后面会继续讲解。

    13040

    Java 并发编程:AQS 的

    与互斥类似,保证了公共数据在任意时刻最多只能由一条线程获取使用,不同的是在获取失败后会采取的处理方式。 是一种非阻塞,它的核心机制就在两个字,即用操作来替代阻塞操作。 特点的核心机制就是死等,所有想要获得的线程都在不停尝试去获取,当然这也会引来竞争问题。与互斥一样,也只允许一个线程获得适用于持有时间叫短的场景,即保护临界区很小的常见,这个很容易理解,如果持有太久,那么将可能导致大量线程都在,浪费大量CPU资源。 如此一来,没获得的线程也不会被挂起或阻塞,而是不断循环检查状态。AQS的机制AQS框架中不管是互斥还是共享实现的基础思想都是基于的机制,不过它对做了优化,这个后面会继续讲解。

    35860

    转:(spinlock)

    与互斥有点类似,只是不会引起调用者睡眠,如果已经被别的执行单元保持,调用者就一直循环在那里看是否该的保持者已经释放了一词就是因此而得名。   由于使用者一般保持时间非常短,因此选择而不是睡眠是非常必要的,的效率远高于互斥。   如果在获取时,没有任何执行单元保持该,那么将立即得到;如果在获取已经有保持者,那么获取操作将在那里,直到该的保持者释放了。   无论是互斥,还是,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得。  的API有:spin_lock_init(x)  该宏用于初始化x。 spin_lock(lock)  该宏用于获得lock,如果能够立即获得,它就马上返回,否则,它将在那里,直到该的保持者释放,这时,它获得并返回。总之,只有它获得才返回。

    24510

    C++多线程-

    是SMP中经常使用到的一个。所谓的smp,就是对称多处理器的意思。在工业用的pcb板上面,特别是服务器上面,一个pcb板有多个cpu是很正常的事情。 我们可以看一段Linux 下的的代码(kernel 2.6.23,asm-i386spinlock.h),就可有清晰的认识了,static inline void __raw_spin_lock( 3,即获得 line 6: 位置符 line 7: lock->slock此时为负数,说明已经被其他cpu抢占了,cpu休息一会,相当于pause指令 line 8: 继续将lock->slock 所以,如果其他的cpu之间没有获得访问权限,就会不断地查看当前是否可以再次申请了。这个过程中间不会停歇,除非获得访问的权限为止。 总结: 1)在smp上是多cpu互斥访问的基础 2)因为等待的,所以处于临界区的代码应尽可能短 3)上面的LOCK_PREFIX,在x86下面其实就是“lock”,gcc下可以编过,朋友们可以己试试

    59910

    Synchronized 偏向、轻量级消除

    而当前线程便尝试使用来获取就是为了不让线程阻塞,而采用循环去获取的过程。? 四、其他优化 1、适应性(Adaptive Spinning):从轻量级获取的流程中我们知道,当线程在获取轻量级的过程中执行CAS操作失败时,是要通过来获取重量级的。 问题在于,是需要消耗CPU的,如果一直获取不到的话,那该线程就一直处在状态,白白浪费CPU资源。 但是JDK采用了更聪明的方式——适应性,简单来说就是线程如果成功了,则下次的次数会更多,如果失败了,则的次数就会减少。 轻量级 竞争的线程不会阻塞,提高了程序的响应速度。 如果始终得不到竞争的线程使用会消耗CPU。 追求响应时间。 同步块执行速度非常快。 重量级 线程竞争不使用,不会消耗CPU。

    30110

    公平非公平可重入

    JAVA中我们知道有很多加的方式,比如常见的 通过synchronized关键字,还有Lock,还有之前说原子CAS操作时有看到过的死循环方式的。 获取了method1方法的之后调用method2会动获取。看以下代码来确定以下是否是这样的。? (spinlock):是指尝试获取的线程不会立即进行阻塞,而是采用循环的方式去尝试获取,这样的好处是减少了线程之间的上下文切换消耗,缺点是循环会消耗CPU性能。 那我们就根据他所提供的方法来己写一个,借此来复习一下之前的原子类操作知识点。 我们可以看到线程B在A释放之后才成功的获取到了。以上就是通过CAS原子操作实现的一个CAS

    28521

    第37问: 着人就糊涂了

    实验首先我们要知道的优点:要上时,如果需要等待其他线程释放,那么:在等待的过程中会先线程会先一段时间阶段,线程不会放弃 CPU过后:如果可以获取了,那么响应会比较快(没发生上下文切换 )如果还需要等待,再用更高成本的方式进行等待innodb_spin_wait_delay 参数决定了阶段的长度。 查询一下等待成本最高的:?可以看到等待成本最高的是 lock_mutex,是保护 MySQL 系统的下面我们来调整一下 innodb_spin_wait_delay,让的时间变长:? 我们让阶段增加了 10 倍,等待的时间也会随之增大。目前的实验看上去阶段越短越好,那么阶段是不是就没有意义了?当然不会。 大家可以将 innodb_spin_wait_delay 设置为 1,再进行测试,随着阶段的减少,等待的时间也会随之增大(大部分都使用了高成本的方式来进行等待)。那么如何选择的参数呢?

    10520

    死磕Java并发:深入分析synchronized的实现原理

    4、优化JDK1.6对的实现引入了大量的优化,如、适应性消除、粗化、偏向、轻量级等技术来减少操作的开销。 所以说,等待的时间(的次数)必须要有一个限度,如果超过了定义的时间仍然没有获取到,则应该被挂起。 同时的默认次数为10次,可以通过参数-XX:PreBlockSpin来调整。如果通过参数-XX:preBlockSpin来调整次数,会带来诸多不便。 6、适应JDK 1.6引入了更加聪明的,即适应。所谓适应就意味着的次数不再是固定的,它是由前一次在同一个上的时间及的拥有者的状态来决定。它怎么做呢? 反之,如果对于某个,很少有能够成功的,那么在以后要或者这个的时候的次数会减少甚至省略掉过程,以免浪费处理器资源。

    21670

    【死磕Java并发】-----深入分析synchronized的实现原理

    与一切皆对象一样,所有的Java对象是天生的Monitor,每一个Java对象都有成为Monitor的潜质,因为在Java的设计中 ,每一个Java对象打娘胎里出来就带了一把看不见的,它叫做内部或者 优化jdk1.6对的实现引入了大量的优化,如、适应性消除、粗化、偏向、轻量级等技术来减少操作的开销。 所以说,等待的时间(的次数)必须要有一个限度,如果超过了定义的时间仍然没有获取到,则应该被挂起。 适应JDK 1.6引入了更加聪明的,即适应。所谓适应就意味着的次数不再是固定的,它是由前一次在同一个上的时间及的拥有者的状态来决定。它怎么做呢? 反之,如果对于某个,很少有能够成功的,那么在以后要或者这个的时候的次数会减少甚至省略掉过程,以免浪费处理器资源。

    49570

    【死磕Java并发】-----深入分析synchronized的实现原理

    与一切皆对象一样,所有的Java对象是天生的Monitor,每一个Java对象都有成为Monitor的潜质,因为在Java的设计中 ,每一个Java对象打娘胎里出来就带了一把看不见的,它叫做内部或者 优化jdk1.6对的实现引入了大量的优化,如、适应性消除、粗化、偏向、轻量级等技术来减少操作的开销。 所以说,等待的时间(的次数)必须要有一个限度,如果超过了定义的时间仍然没有获取到,则应该被挂起。 适应JDK 1.6引入了更加聪明的,即适应。所谓适应就意味着的次数不再是固定的,它是由前一次在同一个上的时间及的拥有者的状态来决定。它怎么做呢? 反之,如果对于某个,很少有能够成功的,那么在以后要或者这个的时候的次数会减少甚至省略掉过程,以免浪费处理器资源。

    20530

    扫码关注云+社区

    领取腾讯云代金券