自旋

synchronized和lock比较浅析

…衆ロ難τιáo~ 提交于 2020-01-30 00:53:26
synchronized是基于jvm底层实现的数据同步,lock是基于Java编写,主要通过硬件依赖CPU指令实现数据同步。下面一一介绍 一、 synchronized 的实现方案   1. synchronized能够把任何一个非null对象当成锁,实现由两种方式:   a.当synchronized作用于非静态方法时,锁住的是当前对象的事例,当synchronized作用于静态方法时,锁住的是class实例,又因为 Class的相关数据存储在永久带,因此静态方法锁相当于类的一个全局锁。   b.当 synchronized作用于一个对象实例时,锁住的是对应的代码块。   2.synchronized锁又称为对象监视器(object)。 3.当多个线程一起访问某个对象监视器的时候,对象监视器会将这些请求存储在不同的容器中。   > Contention List:竞争队列,所有请求锁的线程首先被放在这个竞争队列中   > Entry List: Contention List中那些有资格成为候选资源的线程被移动到 Entry List中   > Wait Set:哪些调用 wait方法被阻塞的线程被放置在这里   > OnDeck:任意时刻,最多只有一个线程正在竞争锁资源,该线程被成为 OnDeck   > Owner:当前已经获取到所资源的线程被称为 Owner   >

java锁优化

为君一笑 提交于 2020-01-28 21:18:53
一、锁优化的思路和方法 锁优化是指:在多线程的并发中当用到锁时,尽可能让性能有所提高。一般并发中用到锁,就是阻塞的并发,前面讲到一般并发级别分为阻塞的和非阻塞的(非阻塞的包含:无障碍的,无等待的,无锁的等等),一旦用到锁,就是阻塞的,也就是一般最糟糕的并发,因此锁优化就是在堵塞的情况下去提高性能;所以所锁的优化就是让性能尽可能提高,不管怎么提高,堵塞的也没有无锁的并发底。让锁定的障碍降到最低,锁优化并不是说就能解决锁堵塞造成的性能问题。这是做不到的。 方法如下:  减少锁持有时间  减小锁粒度  锁分离  锁粗化  锁消除 二、减少锁持有时间 举例: public synchronized void syncMethod(){ othercode1(); mutextMethod(); othercode2(); } 使用这个锁会造成其他线程进行等待,因此让锁的的持有时间减少和锁的范围,锁的零界点就会降低,其他线程就会很快获取锁,尽可能减少了冲突时间。 改进优化如下: public void syncMethod2(){ othercode1(); synchronized(this){ mutextMethod(); } othercode2(); } 三、减小锁粒度  将大对象,拆成小对象,好处是:大大增加并行度,降低锁竞争(同时偏向锁,轻量级锁成功率提高) 

java中常用的锁机制

*爱你&永不变心* 提交于 2020-01-28 20:44:38
基础知识 基础知识之一:锁的类型 锁就那么几个,只是根据特性,分为不同的类型 锁的概念 在计算机科学中,锁(lock)或互斥(mutex)是一种同步机制,用于在有许多执行线程的环境中强制对资源的访问限制。锁旨在强制实施互斥排他、并发控制策略。 锁通常需要硬件支持才能有效实施。这种支持通常采取一个或多个原子指令的形式,如"test-and-set", "fetch-and-add" or "compare-and-swap"”。这些指令允许单个进程测试锁是否空闲,如果空闲,则通过单个原子操作获取锁。 锁的三个概念 1、锁开销 lock overhead 锁占用内存空间、 cpu初始化和销毁锁、获取和释放锁的时间。程序使用的锁越多,相应的锁开销越大 2、锁竞争 lock contention 一个进程或线程试图获取另一个进程或线程持有的锁,就会发生锁竞争。锁粒度越小,发生锁竞争的可能性就越小 3、死锁 deadlock 至少两个任务中的每一个都等待另一个任务持有的锁的情况锁粒度是衡量锁保护的数据量大小,通常选择粗粒度的锁(锁的数量少,每个锁保护大量的数据),在当单进程访问受保护的数据时锁开销小,但是当多个进程同时访问时性能很差。因为增大了锁的竞争。相反,使用细粒度的锁(锁数量多,每个锁保护少量的数据)增加了锁的开销但是减少了锁竞争。例如数据库中,锁的粒度有表锁、页锁、行锁、字段锁

线程安全与锁优化

你说的曾经没有我的故事 提交于 2020-01-27 16:42:25
1.线程安全: 当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方法进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象就是线程安全的。 2.Java语言中的线程安全  根据线程安全的安全程度由强到弱来排序,我们可以把Java语言中各种操作共享的数据分为以下5类:不可变、绝对线程安全、相对线程安全、线程兼容和线程对立。    1)不可变: 不可变的对象一定是线程安全的;Java语言中,如果共享数据是一个基本数据类型,那么只要在定义时使用final关键字修饰它就可以保证它是不可变的。如果共享数据是一个对象,那就需要保证对象的行为不会对其状态产生任何影响,即把对象中带有状态的变量都声明为final,这样在构造函数结束之后,它就是不可变的。    2)绝对线程安全: 就是一个类在任何运行时环境下,调用者都不需要任何额外的同步措施。在Java API中标注自己是线程安全的类,大多数都不是绝对线程安全的。    3)相对线程安全: 就是我们通常所讲的线程安全,它需要保证对这个对象单独的操作是线程安全的,我们在调用时不需要做额外的保障措施。但对于一些特定顺序的连续调用,就可能需要在调用端使用额外的同步手段来保证调用的正确性。    4)线程兼容: 指对象本身并不是线程安全的

synchronized底层实现

不打扰是莪最后的温柔 提交于 2020-01-26 17:58:08
1、锁升级的过程   当多个线程同时竞争一个对象监视器时:当前 对象结构 中的 mark word 中是否是 当前线程id ,如果是则当前线程获得 偏向锁 。 如果不是,则通过CAS将当前线程id置换到mark word中,如果成功则获得偏向锁,如果不成功则说明有竞争,升级为轻量级锁。 后续再通过CAS将 线程的指针 放到mark word中,若成功则获得锁,否则升级为 自旋锁 。自旋锁仍然为轻量级锁,不成功升级为重量级锁。 对象结构 :在JVM中,对象在内存中的布局分为三块区域:对象头、实例数据和对齐填充 mark word :存在于对象头中,存储对象的hashcode,锁标识,分代年龄及GC标识等信息 由上图可以看出,为何偏向锁是将线程id放入mark word,轻量级锁为何将锁的指针放入mark word。 偏向锁 :指偏向于第一个访问的线程,在运行过程中,同步锁没有竞争,则会在这个线程的头部加一个标志位,标记为偏向锁,如果发生竞争则会升级为轻量级锁或者重量级锁 自旋锁 :线程请求不到对象锁时不会堵塞,只是自己循环一下等待对象锁的释放。 因为线程的堵塞和唤醒非常消耗内存 ,所以自旋锁可以很好的优化这个问题。 但它只适合等待时间比较短的,而且并发量不高的场景。 2、升级到重量级锁后,如何运行 当多线程竞争时,不满足的条件的线程会进入同步队列,满足条件后进入同步代码

std::future如何实现

瘦欲@ 提交于 2020-01-26 13:00:48
文章目录 引言 猜测 源码分析 结论 引言 C++11中引入了一个异步编程的利器 std::future (虽然javaGDK5中就已经引入了),这显然使我们的异步编程的过程变得即简介又易维护,但学习不能仅停留在知道它是干什么的的阶段,显然正确的使用时机也是我们需要学习的,但是总感觉对其使用有点不得心应手,遂决定简单的看看源码,看看其是如何实现的. 猜测 在看源码之前 首先自己想一想这个过程当然也是极好的 那我们一起来捋一捋吧 其实过程想来简单 就是在线程结束时以一种方式异步通知当前持有std::future的唯一线程(std::future支持移动不支持复制), 怎么做呢,我当时的想法是这样的 1. 条件变量 future对象中设置一个条件变量 在异步线程结束时调用notify_one(),在get()函数中调用wait(),这样可以实现一个简单的异步调用,缺点是需要互斥量,条件变量,一个仅发生一次的过程这样不免有些浪费,wait()操作更是需要加锁解锁,也就是说这样一个完整的过程我们需要加锁解锁各两次,还需要一个notify_one(),但优点也很明显,过程简单,且如果等待时间较长,可以把cpu让给其他工作线程,全局上节省的时间随等待时间加长而变长,但等待时间短的话除了完成功能就没有丝毫优势了. 2. 自旋锁 自旋锁显然也可以解决这个问题,我们只需要设置一个类内的原子变量

C#多线程编程序--聊聊线程

青春壹個敷衍的年華 提交于 2020-01-25 09:27:24
这篇文章主要给您讲解几个基本问题,什么是线程?为什么要用线程?线程万能?这几个问题。我这篇博客是在该系列另外几篇博客之后写的,之所以不往下继续写,而是回到最初的问题,是因为我感觉到我没有很好的讲解开头的部分,没有很好的介绍线程的基础知识,因此有了写这篇博客的想法。本文不会一五一十的介绍线程,那是百度百科和维基百科的事,我的目的是和您坐下来聊一聊,以我自己粗浅的理解,给您简单讲解一下线程的相关内容。读完,您会对线程有个基本的了解,然后你再去看本系列的其他部分,就会简单些,不会一头雾水。 什么是线程?为什么要用线程? 在一个pc中有很多应用,每一个应用都被分配了一块内存,这些内存就是进程。当你在桌面点击不同的应用时,cpu会在这些应用中切换,以保证尽快的响应你的操作。这些进程能够独立运行,彼此互不影响,一个进程出了问题不会影响其他的进程。很多程序为了提升用户的操作体验,会有好几个进程,要开启一个新进程要消耗很多的时间(大概几秒),有没有一个“轻量级”的进程,能让cpu执行它,且不需要那么多的内存?这就是线程。线程相对进程要简单的多,分配一个新线程很快。现在的cpu执行都是以线程为单位来调度的,而不是进程,并且多核处理器可以并行执行多个线程。 线程万能? 线程怎么看都比进程要好很多,那么线程有什么缺点?相对于进程,线程的调度有很多的优势。这就导致有人对线程过分高估,干点什么事都新开个线程

java - 锁的种类及详解

醉酒当歌 提交于 2020-01-24 16:43:49
锁类型 锁根据其特性能够划分出各种各样的锁类型,该文主要介绍以下锁的作用及特性 乐观锁/悲观锁 独享锁/共享锁 互斥锁/读写锁 可重入锁 公平锁/非公平锁 分段锁 偏向锁/轻量级锁/重量级锁 自旋锁 乐观锁/悲观锁 乐观锁与悲观锁并不是特指某两种类型的锁,是人们定义出来的概念或思想,主要是指看待并发同步的角度。 乐观锁:顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS(Compare and Swap 比较并交换,属于计算机底层的CPU原子操作)实现的。 悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。比如Java里面的同步原语synchronized关键字的实现就是悲观锁。 悲观锁适合写操作非常多的场景,乐观锁适合读操作非常多的场景,不加锁会带来大量的性能提升。 乐观锁在Java中的使用,是无锁编程,常常采用的是CAS算法,典型的例子就是java.util.concurrent.atomic包下的原子类

java并发-AbstractQueuedSynchronizer

大城市里の小女人 提交于 2020-01-21 16:48:55
AQS是个什么东西 AbstractQueuedSynchronizer 是java并发包下大部分的同步组件的底层基础框架,包括 ReentrantLock 、 Semaphore 、 CountDownLatch 等,有点类似在上文中可以基于 ThreadPoolExecutor 构造FixedThreadPool,CachedThreadPool,SingleThreadExecutor。虽然在开发中很少基于AQS直接开发,但在JUC下的一些标准同步器却难勉会接触到,想要了解上层的同步器(显式锁,闭锁,信号量等)的原理,还是有必要起起AQS的底。 AQS主要做着什么 AQS主要做着如下三件事: 原子性地管理着同步状态,这个同步状态就是多线程进行竞争的资源,多线程下必需保证同一时刻只有一个能成功修改同步状态 维护同步队列: 1)新同步节点进入队尾排队进行等待。2)同步节点释放资源时出队并唤醒下一个同步节点,且被唤醒的节点成为头节点。3)对队列中一些已经取消的节点移出队列 线程的阻塞与解除阻塞: 线程竞争不到同步资源时使线程进入阻塞等待,已释放资源的线程唤醒下后继线程,使后继线程解除阻塞进行资源竞争 AQS的实现基础 变体CLH 整个框架的核心是基于CLH队列(通常用于自旋锁)实现变体的CLH锁,但是使用相同的基本策略,在其节点的前置节点中保留关于线程的一些控制信息

.NET中常见的锁 笔记

依然范特西╮ 提交于 2020-01-21 16:13:42
Lock、Monitor lock和Monitor的区别 1、lock的底层本身是Monitor来实现的,所以Monitor可以实现lock的所有功能。 2、Monitor有TryEnter的功能,可以防止出现死锁的问题,lock没有。 尽管大部分时间您都希望使用 lock 语句,但 Monitor 类可以在需要时给予额外的控制。例如,您可以使用 TryEnter() 而不是 Enter(),并指定一个限定时间,避免无止境地等待锁释放。 Mutex Mutex 是 Monitor 更重量级的版本,依赖于底层的操作系统,提供跨多个进程同步访问资源[1], 是针对 Mutex 进行同步的推荐替代方案。 Mutex只能互斥线程间的调用,但是不能互斥本线程的重复调用 Monitor和Lock多用于锁定被调用端,而Mutex则多用锁定调用端。 ReaderWriterLockSlim http://www.cnblogs.com/08shiyan/p/6423532.html 避免使用短生命周期的ReaderWriterLockSlim对象 尽量减少ReaderWriterLockSlim对象的实例 http://blog.csdn.net/shuliuzh/article/details/32130031 表示用于管理资源访问的锁定状态,可实现多线程读取或进行独占式写入访问