关于锁:消失的死锁从-JSF-线程池满到-JVM-初始化原理剖析-京东云技术团队

一、问题形容在一次上线时,依照失常流程上线后,察看了线上报文、接口可用率十分钟以上,未出现异常状况,后果在上线一小时后忽然收到jsf线程池耗尽的报警,并且该利用一共有30台机器,只有一台机器呈现该问题,迅速下线该机器的jsf接口,复原线上。而后开始排查问题。 报错日志信息:[WARN]2023-04-10 18:03:34.847 [ - ][] |[JSF-23002]Task:java.util.concurrent.FutureTask@502cdfa0 has been reject for ThreadPool exhausted! pool:200, active:200, queue:0, taskcnt: 2159[BusinessPool#:][JSF-SEV-WORKER-225-T-8] 二、问题剖析1、呈现问题起因:a)因为只有一台机器呈现线程池耗尽,其余机器均失常运行。所以第一工夫判断是否为有大量流量负载不平衡导致; b)业务代码存在并发锁; c)业务代码解决工夫较长; d)拜访数据源(如DB、redis)变慢; 排查接口流量UMP监控,依照机器纬度看,发现每个机器流量是平衡的,排除a)项; 排查业务量大的接口UMP KEY监控,依照机器纬度看,失常机器和异样机器耗时基本一致,并于平常统一,无较大差别,排除c)项; 排查数据库监控,无慢sql,读写均无耗时较长的状况,排除d)项; 综上,只剩下b)项,确认问题起因是代码存在并发锁,故开始排查日志及业务代码。 2、依据已确认的起因排查思路:1)down下dump文件,发现极多JSF线程处于RUNNABLE状态,并且堆栈处于SerializersHelper类 "JSF-BZ-22000-223-T-200" #1251 daemon prio=5 os_prio=0 tid=0x00007fd15005c000 nid=0xef6 in Object.wait() [0x00007fce287ac000] java.lang.Thread.State: RUNNABLE at com.jd.purchase.utils.serializer.helper.SerializersHelper.ofString(SerializersHelper.java:79) at com.jd.ldop.pipe.proxy.OrderMiddlewareCBDExportServiceProxy.getAddress(OrderMiddlewareCBDExportServiceProxy.java:97) at com.jd.ldop.pipe.proxy.OrderMiddlewareCBDExportServiceProxy.findOrder(OrderMiddlewareCBDExportServiceProxy.java:211)依据堆栈信息排查代码,发现代码会初始化一个自定义的序列化工厂类:SerializerFactory 并且此时初始化时会打印日志: log.info("register: {} , clazz : {}", serializer.getCode(), serializer.getClass().getName());故依据此日志关键字排查初始化加载日志,发现失常机器都加载了两个序列化对象,只有出问题的那个机器只加载了这一个序列化对象。 于是问题初步定位到出问题的机器初始化ProtoStuffSerializer这个类时失败。 初始化此类时static代码块为: static { STRATEGY = new DefaultIdStrategy(IdStrategy.DEFAULT_FLAGS);}2)开始排查为什么初始化这个类会失败 因为不同机器存在初始化胜利和失败的独立性,首先思考jar包是否抵触 a)于是发现这里存在jar抵触,然而将抵触jar排除后,屡次重启机器后发现仍然存在此ProtoStuffSerializer初始化失败状况。 b)存在死锁,然而失常逻辑下,存在死锁的话,应该所有机器都会存在此类情况,然而此时大略只有5%的几率呈现死锁,并且排查jstack发现200个线程都卡在获取ProtoStuffSerializer。 ...

June 14, 2023 · 3 min · jiezi

关于锁:锁的优化策略

锁的优化策略有以下几种:缩小锁的粒度:将本来粗粒度的锁细化为更细的锁,这样就能缩小竞争和抵触。然而这种策略须要思考细粒度锁的实现和保护老本,以及可能会带来的更多的上下文切换。 防止锁的应用:尝试应用无锁数据结构、乐观锁或无锁算法代替锁,这样能够防止锁带来的性能损失,但也须要思考其适用性和正确性。 锁拆散:在应用锁的状况下,尝试将不同的锁拆散,防止不同的锁之间的竞争和抵触。这种策略须要思考锁的数量和保护老本。 残缺内容请点击下方链接查看: https://developer.aliyun.com/ask/499542?utm_content=g_1000371148 版权申明:本文内容由阿里云实名注册用户自发奉献,版权归原作者所有,阿里云开发者社区不领有其著作权,亦不承当相应法律责任。具体规定请查看《阿里云开发者社区用户服务协定》和《阿里云开发者社区知识产权爱护指引》。如果您发现本社区中有涉嫌剽窃的内容,填写侵权投诉表单进行举报,一经查实,本社区将立即删除涉嫌侵权内容。

April 28, 2023 · 1 min · jiezi

关于锁:Java常见锁

乐观锁 乐观锁是一种乐观思维,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为他人不会批改,所以不会上锁,然而在更新时会判断此期间数据是否被更新采取在写时先读出以后版本号,而后加锁操作(比拟跟上一次的版本号,如果一样则更新),如果失败则要反复读-比拟-写的操作 java中的乐观锁根本通过 CAS 操作实现的,CAS 是一种更新的原子操作,比拟以后值跟传入值是否一样,一样则更新,否则失败乐观锁 乐观锁是就是乐观思维,即认为写多,遇到并发写的可能性高,每次去拿数据的时候都认为他人会批改,所以每次在读写数据的时候都会上锁,这样他人想读写这个数据就会block 直到拿到锁 Java 中的乐观锁就是SynchronizedAQS 框架下的锁则是先尝试 cas 乐观锁去获取锁,获取不到,才会转换为乐观锁,如 RetreenLock自旋锁 原理自旋锁原理非常简单,如果持有锁的线程能在很短时间内开释锁资源,那么那些期待竞争锁的线程就不须要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需自旋,等持有锁的线程开释锁后即可立刻获取锁,这样就防止用户线程和内核的切换的耗费。线程自旋需耗费 cup的,如果始终获取不到锁,则线程长时间占用CPU自旋,须要设定一个自旋期待最大事件在最大等待时间内仍未取得锁就会进行自旋进入阻塞状态。自旋锁优缺点 长处自旋锁尽可能的缩小线程的阻塞,这对于锁的竞争不强烈,且占用锁工夫十分短的代码块来说性能能大幅度的晋升,因为自旋的耗费会小于线程阻塞挂起再唤醒的操作的耗费(这些操作会导致线程产生两次上下文切换)毛病 锁竞争强烈或者持有锁的线程须要长时间占用锁执行同步块,不适宜应用自旋锁了,因为自旋锁在获取锁前始终都是占用 cpu做无用功,同时有大量线程在竞争一个锁,会导致获取锁的工夫很长,线程自旋的耗费大于线程阻塞挂起操作的耗费,其它须要 cup 的线程又不能获取到cpu,造成 cpu 的节约自旋锁工夫阈值(1.6 引入了适应性自旋锁)自旋锁的目标是为了占着 CPU 的资源不开释,等到获取到锁立刻进行解决 自旋执行工夫太长,会有大量的线程处于自旋状态占用 CPU资源,进而会影响整体零碎的性能 JVM 对于自旋周期的抉择,jdk1.5 这个限度是肯定的写死的 在 1.6引入了适应性自旋锁,自旋的工夫不固定,而是由前一次在同一个锁上的自旋工夫以及锁的拥有者的状态来决定,根本认为一个线程上下文切换的工夫是最佳的一个工夫自旋锁的开启 JDK1.6 中-XX:+UseSpinning 开;XX:PreBlockSpin=10 为自旋次数 JDK1.7 后,去掉此参数,由jvm 管制Synchronized 同步锁 关键字,用于解决多个线程间拜访资源同步性问题,保障其润饰的办法或代码块任意时刻只能有一个线程拜访synchronized 它能够把任非NULL 的对象当作锁。他属于独占式乐观锁,同时属于可重入锁。Synchronized作用范畴 作用实例办法时。锁住的是对象的实例(this) 作用静态方法时,锁住的是该类,该 Class所有实例,又因为 Class的相干数据存储在永恒带 PermGen(jdk1.8 则是 元空间),永恒带是全局共享的,因而静态方法锁相当于类的一个全局锁,会锁所有调用该办法的线程.线程A调用一个实例对象非动态Synchronized办法,容许线程B调用该实例对象所属类的动态s办法而不会产生互斥,前者锁的是以后实例对象,后者锁的是以后类 作用于同步代码块 锁住的以后对象,进入同步代码块前须要取得对象的锁Synchronized实现 Synchronized 是一个重量级操作,须要调用操作系统相干接口,性能是低效的,有可能给线程加锁耗费的工夫比有用操作耗费的工夫更多。Java1.6,synchronized 进行了很多的优化,有适应自旋、锁打消、锁粗化、轻量级锁及偏差锁等,效率有了实质上的进步。在之后推出的 Java1.7 与 1.8中,均对该关键字的实现机理了优化。引入了偏差锁和轻量级锁,都是在对象头中有标记位,不须要通过操作系统加锁JDK1.6后的优化 synchronized是依据JVM实现的,该关键字的优化也是在JVM层面实现 而未间接裸露JDK1.6后对锁做了大量优化如偏差锁,轻量锁,自旋锁,自适应锁等等锁次要有四种状态:无锁状态,偏差锁状态,轻量级锁状态,重量级锁状态,他们会随着锁竞争的强烈而逐步降级且这种降级不可降,利用该策略进步取得锁和开释锁的效率ReentrantLock ReentantLock 继承接口Lock并实现了接口中定义的办法,他是一种可重入锁,除了能实现 synchronized所能实现的所有工作外,还提供了诸如可响应中断锁、可轮询锁申请、定时锁等防止多线程死锁的办法。Lock接口次要办法 void lock(): 执行此办法时, 如果锁处于闲暇状态, 以后线程将获取到锁 lock()办法则是肯定要获取到锁,如果锁不可用,就始终期待, 在未取得锁之前,以后线程并不持续向下执行. boolean tryLock():如果锁可用, 则获取锁, 并立刻返回 true, 否则返回 false. tryLock()只是"试图"获取锁, 如果锁不可用,不会导致以后线程阻塞挂起,以后线程依然持续往下执行代码. void unlock() 解锁 isLock():此锁是否有任意线程占用tryLock 和 lock 和 lockInterruptiblytryLock 能取得锁就返回 true,不能就立刻返回false,tryLock(long timeout,TimeUnitunit),能够减少工夫限度,如果超过该时间段还没取得锁,返回falselock 能取得锁就返回 true,不能的话始终期待取得锁 lock 和 lockInterruptibly,如果两个线程别离执行这两个办法,但此时中断这两线程,但此时中断这两个线程, lock 不会抛出异样,而lockInterruptibly 会抛出异样ReentrantLock 与 synchronized ...

February 28, 2023 · 2 min · jiezi

关于锁:互斥锁和信号量有什么不同译

原文地址 什么是信号量?信号量是一个非负变量, 并且在线程之间共享。信号量是一种信号机制,一个线程正在期待信号量能够由另一个线程收回。它应用两个原子操作,1)wait和 2)signal实现线程同步。 信号量实现容许或不容许拜访资源,这取决于它的设置形式。 什么是互斥锁?互斥的残缺模式是互斥对象。它是一种非凡类型的二进制信号,用于管制对共享资源的拜访。它蕴含了一个优先级继承机制来防止扩大优先级反转问题。它容许以后优先级较高的工作在尽可能短的工夫内放弃在阻塞状态。然而,优先级继承并不能解决优先级反转问题,只能最小化其影响。 次要区别:互斥锁是一种锁机制,信号量是一种信号机制互斥锁是一个对象,信号量是一个整数互斥锁没有子类型,信号量有两种子类型,计数信号量和二进制信号量信号量反对wait和signal操作批改,而互斥锁仅能由可能申请或开释资源的过程批改信号量的值应用wait()和signal()这两个办法批改,而互斥锁应用lock和unlock来操作。应用信号量在单个缓冲区的状况下,咱们能够将4KB的缓冲区分成四个1KB的缓冲区。信号量能够与这四个缓冲区相关联。这容许用户和生产者同时在不同的缓冲区上工作。 应用互斥锁互斥锁提供了互斥的性能,不论是生产者还是消费者,都能够持有锁,持有锁的一方能够持续工作,另一方就要期待,在同一时间,只有一个线程能够解决整个缓冲区。 对于互斥和信号量的常见事实只有一个工作能够获取到互斥锁,互斥锁有所有权,只有持有锁的工作能力开释互斥锁。应用互斥锁和信号量的场景是不同的,然而因为实现形式有相似之处,互斥锁也被称为二进制信号量一个家喻户晓的谬误:互斥量和信号量简直雷同,惟一的区别是互斥量可能计数到1,而信号量可能从0计数到N二进制信号量和互斥量之间总是存在不确定性。你可能据说互斥锁是一个二进制信号量,这是不正确的信号量的长处容许多个线程拜访临界区信号量是独立于机器的(因为它们是在内核服务中实现的)不容许多个过程进入临界区。信号量有忙等状态,因为不会浪费时间和资源互斥锁的长处互斥锁只是简略的锁,在进入临界区是持有它,来到时开释因为在任何给定工夫只有一个线程处于临界区内,因而不存在数据竞争,能够始终保持数据一致性信号量的毛病信号量的最大限度之一是优先级反转问题操作系统必须跟踪所有信号量的调用为了防止信号量中的死锁,wait和signal操作须要以正确的程序执行信号量编程是一种简单的办法,因而有可能无奈实现互斥的成果它也不是能够大规模应用的实用办法,因为它们的应用会毁坏模块化程序员应用信号量更容易出错,容易呈现死锁互斥锁的毛病如果一个持有锁的线程休眠或者被强占了CPU,其余线程就没方法继续执行了一次只能容许一个线程拜访临界区失常实现可能会导致忙期待状态,节约CPU工夫

May 9, 2022 · 1 min · jiezi

关于锁:JDK内置锁深入探究

一、序言本文讲述仅针对 JVM 档次的内置锁,不波及分布式锁。 锁有多种分类模式,比方偏心锁与非偏心锁、可重入锁与非重入锁、独享锁与共享锁、乐观锁与乐观锁、互斥锁与读写锁、自旋锁、分段锁和偏差锁/轻量级锁/重量级锁。 上面将配合示例解说各种锁的概念,冀望可能达到如下指标:一是在生产环境中不谬误的应用锁;二是在生产环境中抉择失当的锁。 对锁理解不多的状况下,应该首先保障业务的正确性,而后思考性能,比方万金油synchronized锁或者自带多重属性的ReentrantReadWriteLock锁。不因并发导致业务谬误,不呈现死锁。 随着对锁的理解增多,须要更加精准的抉择各类锁以保障更高性能要求。 二、锁的分类Java 中有两种加锁的形式:一是 synchronized 关键字,二是用 Lock 接口的实现类。 须要通过加(互斥)锁来解决线程平安问题的锁称之为乐观锁;不通过加锁来解决线程平安问题的锁称之为乐观锁。 锁的性能比拟:互斥锁 < 读写锁、自旋锁 < 乐观锁。 读写锁和自旋锁别离从两个不同角度晋升锁的效率,前者通过共享读锁来提高效率;后者通过回避阻塞-唤醒上下文切换来提高效率。 (一)偏心锁/非偏心锁偏心锁和非偏心锁具体实现类有Semaphore、ReentrantLock和ReentrantReadWriteLock。 偏心与否是指参加竞争的线程是否都有机会取得锁,偏心锁:多个线程依照申请锁的程序来获取锁;非偏心锁并不是依照申请锁的程序来获取锁,极其状况下可能会有线程始终无奈获取到锁。 偏心锁保护一个虚构的先进先出队列,依照秩序排队申请获取锁。 1、概念解读为何按锁的申请程序依照先进先出的程序获取锁可能保障偏心?当采纳先进先出的排队机制时,所有处于期待队列中的线程实践上都有机会取得锁,并且随着工夫的推移,取得锁的机会越来越大。 不是依照申请锁的程序来获取锁如何解读?synchronized 锁是典型的非偏心锁,表现形式是所有参加获取锁的线程是否可能取得锁是不可预测的。 偏心锁的深层次外延是只有线程有取得锁的需要,在相对的工夫里,肯定可能取得锁。比方服务器连贯资源,不存在客户端连贯不上的状况,这是偏心锁的典型的利用。 2、锁代码档次示意Semaphore // 非偏心锁Semaphore unfairLock = new Semaphore(5);// 偏心锁Semaphore fairLock = new Semaphore(5,true);ReentrantLock // 非偏心锁ReentrantLock unfairLock = new ReentrantLock();// 偏心锁ReentrantLock fairLock = new ReentrantLock(true);ReentrantReadWriteLock // 非偏心锁ReentrantReadWriteLock unfairLock = new ReentrantReadWriteLock();// 偏心可锁ReentrantReadWriteLock fairLock = new ReentrantReadWriteLock(true);下面提到的 3 个锁的实现类能配置偏心锁或者非偏心锁,真正实现锁的偏心与否是由AbstractQueuedSynchronizer抽象类的子类定义的。 3、优劣比照锁获取锁事件锁的效率备注偏心锁能够乐观预计绝对较低 非偏心锁饥饿状态绝对较高如果对锁没有特地的要求,优先选用非偏心锁偏心锁的效率比非偏心锁低的起因如下: 所有想获取锁的线程必须先到先进先出队列注册,排队能力获取锁,从获取锁的流程上减少额定的操作;有队列必然波及线程的阻塞与唤醒操作,减少了操作系统档次上下文切换调度开销。(二)可重入锁/非可重入锁可重入锁是指某个线程取得特定锁后,同一个线程内能够屡次取得该锁。synchronized关键字、ReentrantLock和ReentrantReadWriteLock属于可重入锁,Jdk 内置除此之外其它的锁都是不可重入锁。 可重入锁有两个重要的个性:同一个线程、反复获取锁。 1、可重入锁必要性剖析可重入锁可能防止同一线程屡次获取锁时的死锁景象。 ...

April 20, 2022 · 2 min · jiezi

关于锁:多线程学习锁升级

前言本篇文章次要学习synchronized关键字在JDK1.6引入的偏差锁和轻量级锁,并围绕synchronized关键字的锁的降级进行展开讨论。本篇文章探讨的锁是通过synchronized加的锁,是不同于java.util.concurrent.locks.Lock的另外一种加锁机制,后续文中提及锁,均指synchronized关键字的锁。 参考资料:《Java并发编程的艺术》 注释一. 锁的应用synchronized能够用于润饰一般办法,静态方法和代码块,拜访被synchronized关键字润饰的内容须要先获取锁,获取的这个锁具体是什么,这里暂不探讨,上面先举例子来看一下synchronized关键字如何应用。 public class SynchronizedLearn { //润饰一般办法 public synchronized void normalSyncMethod() { ...... } //润饰静态方法 public static synchronized void staticSyncMethod() { ...... } //润饰代码块 public void syncCodeBlock() { synchronized (SynchronizedLearn.class) { ...... } }}上述例子中,应用synchronized关键字润饰代码块时,传入了SynchronizedLearn类的类对象,实际上,synchronized关键字无论是润饰办法还是润饰代码块,均须要传入一个对象,咱们这里能够将传入的这个对象了解为锁,只不过在润饰办法时,会隐式地传入对象作为锁,规定如下。 润饰一般办法时,隐式传入的对象为持有一般办法的实例对象自身;润饰静态方法时,隐式传入的对象为持有静态方法的类的类对象。咱们称由synchronized关键字润饰的办法为同步办法,联合上述规定,对由synchronized关键字润饰的同步办法的拜访有如下留神点。 1. 实例对象的所有一般同步办法同一时刻只能由一个线程拜访给出一个例子如下所示。 public class SynchronizedLearn { public synchronized void normalSyncMethod1() { ...... } public synchronized void normalSyncMethod2() { ...... }}某时刻线程A和线程B都持有SynchronizedLearn的同一个实例synchronizedLearn,并且线程A胜利调用实例synchronizedLearn的normalSyncMethod1()办法,此时在线程A执行完normalSyncMethod1()办法以前,线程B都无法访问normalSyncMethod1()和normalSyncMethod2()办法。 2. 类的所有动态同步办法同一时刻只能由一个线程拜访给出一个例子如下所示。 public class SynchronizedLearn { public static synchronized void staticSyncMethod1() { ...... } public static synchronized void staticSyncMethod2() { ...... }}某时刻线程A胜利调用SynchronizedLearn类的staticSyncMethod1()办法,此时在线程A执行完staticSyncMethod1()办法以前,线程B都无法访问staticSyncMethod1()和staticSyncMethod2()办法。 ...

September 2, 2021 · 2 min · jiezi

关于锁:多线程学习队列同步器

前言AbstractQueuedSynchronizer,即队列同步器,通过继承AbstractQueuedSynchronizer并重写其办法能够实现锁或其它同步组件,本篇文章将对AbstractQueuedSynchronizer的应用和原理进行学习。 参考资料:《Java并发编程的艺术》 注释一. AbstractQueuedSynchronizer的应用AbstractQueuedSynchronizer的应用通常如下。 创立AbstractQueuedSynchronizer的子类作为同步组件(例如ReentrantLock和CountDownLatch等)的动态外部类并重写AbstractQueuedSynchronizer规定的可重写的办法;同步组件通过调用AbstractQueuedSynchronizer提供的模板办法来实现同步组件的同步性能。先对AbstractQueuedSynchronizer的可重写的办法进行阐明。AbstractQueuedSynchronizer是基于模板设计模式来实现锁或同步组件的,AbstractQueuedSynchronizer外部保护着一个字段叫做state,该字段示意同步状态,是一个整型变量,AbstractQueuedSynchronizer规定了若干办法来操作state字段,但AbstractQueuedSynchronizer自身并没有对这些办法进行实现,而是要求AbstractQueuedSynchronizer的子类来实现这些办法,上面看一下这些办法的签名和正文。 办法签名正文protected boolean tryAcquire(int arg)独占式地获取同步状态。该办法在独占式获取同步状态以前应该判断是否容许独占式获取,如果容许则尝试基于CAS形式来设置同步状态,设置胜利则示意获取同步状态胜利。protected boolean tryRelease(int arg)独占式地开释同步状态。能够了解为将同步状态还原为获取前的状态。protected int tryAcquireShared(int arg)共享式地获取同步状态。protected boolean tryReleaseShared(int arg)共享式地开释同步状态。protected boolean isHeldExclusively()判断以后线程是否独占以后队列同步器。实际上,AbstractQueuedSynchronizer规定的这些可重写的办法,均会被AbstractQueuedSynchronizer提供的模板办法所调用,在基于AbstractQueuedSynchronizer实现同步组件时,可依据同步组件的理论性能来重写这些可重写办法,而后再通过调用模板办法来实现同步组件的性能。上面看一下AbstractQueuedSynchronizer提供的模板办法。 办法签名正文public final void acquire(int arg)独占式获取同步状态,即独占式获取锁。获取胜利则该办法返回,获取失败则以后线程进入同步队列期待。public final void acquireInterruptibly(int arg) throws InterruptedException独占式获取同步状态,并响应中断。即如果获取同步状态失败,则会进入同步队列期待,此时如果线程被中断,则会退出期待状态并抛出中断异样。public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException同acquireInterruptibly(int arg),并在其根底上指定了等待时间,若超时还未获取同步状态则返回false。public final void acquireShared(int arg)共享式获取同步状态,即共享式获取锁。获取胜利则该办法返回,获取失败则以后线程进入同步队列期待,反对同一时刻多个线程获取到同步状态。public final void acquireSharedInterruptibly(int arg) throws InterruptedException共享式获取同步状态,并响应中断。public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException同acquireSharedInterruptibly(int arg),并在其根底上指定了等待时间,若超时还未获取同步状态则返回false。public final boolean release(int arg)独占式地开释同步状态,即独占式地开释锁。胜利开释锁之后会将同步队列中的第一个节点的线程唤醒。public final boolean releaseShared(int arg)共享式地开释同步状态。public final Collection<Thread> getQueuedThreads()获取在同步队列上期待地线程。上面联合《Java并发编程的艺术》中的例子的简化版,来直观的展现应用AbstractQueuedSynchronizer来实现同步组件的不便,如下所示。 ...

August 14, 2021 · 4 min · jiezi

关于锁:第43问锁用得太多-为什么要调整-Buffer-Pool

问当咱们应用一个事务操作很多数据时, MySQL 有时会报错: The total number of locks exceeds the lock table size 依据官网文档, 咱们须要调大 buffer pool 的大小: 本期试验, 咱们来摸索一下锁用得多与 buffer pool 大小的关系 试验咱们用老办法建一个数据库, 并将 buffer pool 大小调整到了最小值5M, 不便咱们复现问题 当初来模仿一个用锁特地多的事务: 咱们还是用老办法让表翻倍, 来不停地占用锁. 看一下成果: 咱们能够通过 information_schema.INNODB_TRX 来查看事务应用了多少锁, 解释一下上图中标记的这几个状态: trx_tables_locked: 该事务锁了几张表trx_rows_locked: 该事务锁了多少数据行trx_lock_structs: 该事务一共用到了多少个锁构造.一个锁构造用于锁住多个表或多个行trx_lock_memory_bytes: 该事务的锁构造一共用了多少内存再来看看 buffer pool 的状态: 解释一下 Buffer pool 的这两个状态: total 是 Buffer pool 的总页数misc 是 Buffer pool 中非数据页的页数咱们持续造数据, 让该事务应用的锁越来越多, 再来看看状态: 与最后的状态相比, 该事务应用的锁的内存增长了 (1269968 - 24784 = ) 1245184 字节 = 1216 k, 而 buffer pool 非数据页多应用了 (84-8 = ) 76页, 每页16k, 总共 1216 k ...

August 6, 2021 · 1 min · jiezi

关于锁:技术分享-MySQL中查询会锁表

作者:刘晨 网名 bisal ,具备十年以上的利用运维工作教训,目前次要从事数据库利用研发能力晋升方面的工作,Oracle ACE ,领有 Oracle OCM & OCP、EXIN DevOps Master 、SCJP 等国内认证,国内首批 Oracle YEP 成员,OCMU 成员,《DevOps 最佳实际》中文译者之一,CSDN & ITPub 专家博主,公众号"bisal的集体杂货铺",长期保持分享技术文章,屡次在线上和线下分享技术主题。 本文起源:原创投稿 *爱可生开源社区出品,原创内容未经受权不得随便应用,转载请分割小编并注明起源。 咱们晓得,Oracle 中除了应用 select ... for update ,其余查问语句不会呈现锁,即没有读锁,读一致性通过多版本解决的,能够保障在不加锁的状况下,读到同一时间的数据。 前两天共事在微信群推了一篇文章,大略意思就是通过应用 insert into select 做了数据的备份,导致了 select 的表锁住,进而影响了失常的应用。 问题来了,Oracle 中执行的 insert into select 很失常,不会呈现锁表,难道雷同的语句用在了 MySQL ,就会锁住整张表? 咱们能进行验证,MySQL 5.7 中执行如下语句,会呈现什么景象? insert into test_1 select * from test_2;test_1 和 test_2 定义如下,test_1 存在五条记录, mysql> show create table test_1\G;*************************** 1. row *************************** Table: test_1Create Table: CREATE TABLE `test_1` ( `id` int(11) NOT NULL, `name` varchar(10) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb41 row in set (0.04 sec)mysql> show create table test_2\G;*************************** 1. row *************************** Table: test_2Create Table: CREATE TABLE `test_2` ( `id` int(11) NOT NULL, `name` varchar(10) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb41 row in set (0.01 sec)mysql> select * from test_1;+----+--------+| id | name |+----+--------+| 1 | test_1 || 2 | test_2 || 3 | test_3 || 4 | test_4 || 5 | test_5 |+----+--------+5 rows in set (0.01 sec)默认状况下,show engine innodb status 显示的锁信息很无限,能够开启锁监控,如果仅须要在 show engine innodb status 显示具体的锁,能够仅关上 innodb_status_output_locks, ...

June 8, 2021 · 7 min · jiezi

关于锁:第38问分区表到底要上多少锁

问为什么我应用分区表, 有时候是几个锁, 有时候是几百把锁, 阴晴不定 试验咱们先宽油起一个数据库: 建一个分区表: 咱们心愿依据 timestamp 的日期进行分区, id 作为主键. 因为分区键必须是主键, 所以咱们将 timestamp 退出主键中. 上面咱们来钻研一下应用分区表时, 分区表到底会用多少个锁. 先插入两条数据: 场景1:咱们用 RC 隔离级别, 锁定 id = 1 的记录 此时, 查看锁信息: 能够看到: 因为咱们在 where 条件里没有用到分区键 timestamp, 那么 MySQL 要拜访每张表, 就须要给每张表上IX锁. 场景2:这次咱们换成 RR 隔离级别: 查看锁信息: 这次锁数量变成了 64 个, 每个分区表上锁住了 supremum 的 gap 区间. 这很好了解: 咱们让 MySQL 锁住了所有 id=1 可能呈现的中央, 这就包含了所有分区中相干间隙. 场景3:这次咱们在 where 条件里用到分区键: 查看锁信息: ...

June 4, 2021 · 1 min · jiezi

关于锁:做开发这几种锁机制你不得不了解一下

摘要:并发访问共享资源,如果不加锁,可能会导致数据不统一问题,通常为了解决并发拜访问题,咱们都会在访问共享资源之前加锁,保障同一时刻只有一个线程拜访。上面咱们用问答的形式阐明下各种并发锁的概念、优缺点及其利用场景。本文分享自华为云社区《一文带你全面了解各种锁机制》,原文作者:dayu_dls。 并发访问共享资源,如果不加锁,可能会导致数据不统一问题,通常为了解决并发拜访问题,咱们都会在访问共享资源之前加锁,保障同一时刻只有一个线程拜访。上面咱们用问答的形式阐明下各种并发锁的概念、优缺点及其利用场景。 1、什么是互斥锁和自旋锁,各有什么优缺点?互斥锁和自旋锁是最底层的两种锁,其余的很多锁都是基于他们的实现。当线程A获取到锁后,线程B再去获取锁,有两种解决形式,第一种是线程B循环的去尝试获取锁,直到获取胜利为止即自旋锁,另一种是线程B放弃获取锁,在锁闲暇时,期待被唤醒,即互斥锁。 互斥锁会开释以后线程的cpu,导致加锁的代码阻塞,直到线程再次被唤醒。互斥锁加锁失败时,会从用户态陷入到内核态,让内核帮咱们切换线程,存在肯定的性能开销。 (1)当线程加锁失败,内核会把线程的状态由“运行”设置为“睡眠”,让出cpu;(2)当锁闲暇时,内核唤醒线程,状态设置为“就绪”,获取cpu执行;而自旋锁会自用户态由应用程序实现,不波及用户态到内核态的转化,没有线程上下文切换,性能绝对较好。自旋锁加锁过程: (1)查看锁的状态;(2)锁闲暇,获取锁,否则执行(1);自旋锁会利用cpu始终工作直到获取到锁,两头不会开释cpu,但如果被锁住的代码执行工夫较长,导致cpu空转,浪费资源。 2、什么是读写锁?读写锁由读锁和写锁组成。读锁又称为共享锁,S锁,写锁又称为排它锁、X锁,在mysql的事务中大量应用。写锁是独占锁,一旦线程获取写锁,其余线程不能获取写锁和读锁。 读锁是共享锁,当线程获取读锁,其余线程能够获取读锁不能获取写锁。因为并发数据读取并不会扭转共享数据导致数据不统一。读写锁把对共享资源的读操作和写操作别离加锁管制,可能进步读线程的并发性,实用于读多写少的场景。 3、什么是读优先锁、写优先锁、偏心读写锁?读优先锁心愿的是读锁可能被更多的线程获取,能够进步读线程的并发性。线程A获取了读锁,线程B想获取写锁,此时会被阻塞,线程c能够持续获取读锁,直到A和c开释锁,线程B才能够获取写锁。如果有很多线程获取读锁,且加锁的代码执行工夫很长,就到导致线程B永远获取不到写锁。 写优先锁心愿的是写锁可能被优先获取。线程A获取了读锁,线程B想获取写锁,此时会被阻塞,前面获取读锁都会失败,线程A开释锁,线程B能够获取写锁,其余获取读锁的线程阻塞。如果有很多写线程获取写锁,且加锁的代码执行工夫很长,就到导致读线程永远获取不到读锁。 下面两种锁都会造成【饥饿】景象,为解决这种问题,能够减少一个队列,把获取锁的线程(不论是写线程还是读线程)依照先进先出的形式排队,每次从队列中取出一个线程获取锁,这种获取锁的形式是偏心的。 4、什么是乐观锁和乐观锁?乐观锁是先批改共享资源,再用历史数据和以后数据比对验证这段时间共享数据有没有被批改,如果没有被批改,那么更新数据,如果有其余线程更新了共享资源,须要从新获取数据,再更新,验证,周而复始的重试,直到更新胜利。所以当数据更新操作比拟频繁,数据抵触的概率就会比拟大,重试的次数就会多,节约CPU资源。 乐观锁其实全程没有加锁,也叫无锁编程,所以针对读多写少的场景,并发性能较高,典型的实现MVCC,mysql中会应用MVCC构建一致性读来保障可反复读。乐观锁是在访问共享资源之前通通加锁。当并发抵触概率较高时,乐观锁不在实用,乐观锁就排上用场。互斥锁、自旋锁都是乐观锁的实现。 点击关注,第一工夫理解华为云陈腐技术~

May 25, 2021 · 1 min · jiezi

关于列表解析:技术实践丨列存表并发更新时的锁等待问题原理

摘要:当开启transaction,执行updata的语句执行胜利,不执行commit或rollback;再开启另一个窗口,执行upadate语句,会呈现失败(报错:锁期待超时)的状况,然而如果对于上一个窗口执行rollback,此窗口update能够执行胜利,该种状况应思考该表是否为列存表。本文分享自华为云社区《列存表并发更新时时的锁期待问题原理》,原文作者:PFloyd 。 当开启transaction,执行updata的语句执行胜利,不执行commit或rollback;再开启另一个窗口,执行upadate语句,会呈现失败(报错:锁期待超时)的状况,然而如果对于上一个窗口执行rollback,此窗口update能够执行胜利,该种状况应思考该表是否为列存表。 【问题根因】如果应用的是列存表,在事务中执行update操作时,是以CU为单位进行加锁的,所以在事务未提交时并发更新同一CU的其余数据时会呈现锁期待的状况,期待超时的时候会呈现报错 【机制原理】1.CU为压缩单元(Compress Unit),列存储的最小单位,导入数据时生成,生成后数据固定不可更改,单个CU最多存储1列60000行数据。同一列的CU间断存储在一个文件中,当大于1G时,切换到新文件中。其中的Ctid字段标识列存表的一行,由cu_id和CU外行号(cu_id, offset)组成;一次性写入的多条的数据位于同一CU。 2. 为了避免页面同一个元组被两个事务同时更新,在进行update时,都会加上行级锁,对于行存来说是对一行数据加锁,对于列存来说就是对一个CU加锁,当一个事务update未提交时,其余事务是无奈同时去更新同一CU的数据的。 3.进行update操作后,旧元组被标记为deleted,新元组会写到一个新的CU中 【案例剖析】1.依据现场的报错信息,能够确定是并发更新报错;进行update时,会申请行级锁,在申请行级锁之前会申请transactionid锁,期待超时后报错信息为:waiting for ShareLock on transaction xxx after ..ms 2.客户反馈更新的并不是同一条数据,id不同,询问客户后得悉呈现问题的是列存表,查问更新的数据是否处于同一CU。 查问后发现处于同一CU,合乎预期。 3.本地场景复现: 起事务执行update操作: 事务未提交并发更新数据呈现期待: 查问后发现两条数据位于同一cu: 【相干问题】为什么update胜利一次之后,下一次update就不会相互等锁了? 这是因为update胜利之后,旧数据被标记为deleted,新数据写入新的CU,这两条数据不再是同一个CU了,也就不存在这种锁抵触 【解决计划】列存表不适宜频繁的update场景,列存频繁的update容易触发并发更新等锁超时,并且会导致小CU过多,而每个CU都会扩大至8192字节进行对齐,从而导致磁盘空间迅速收缩;频繁的点查或频繁update场景倡议应用行存表。 点击关注,第一工夫理解华为云陈腐技术~

April 17, 2021 · 1 min · jiezi

关于物联网:一文带你剖析LiteOS互斥锁Mutex源代码

摘要:多任务环境下会存在多个工作拜访同一公共资源的场景,而有些公共资源是非共享的临界资源,只能被独占应用。LiteOS应用互斥锁来防止这种抵触,互斥锁是一种非凡的二值性信号量,用于实现对临界资源的独占式解决。本文分享自华为云社区《LiteOS内核源码剖析系列七 互斥锁Mutex》,原文作者:zhushy。 多任务环境下会存在多个工作拜访同一公共资源的场景,而有些公共资源是非共享的临界资源,只能被独占应用。LiteOS应用互斥锁来防止这种抵触,互斥锁是一种非凡的二值性信号量,用于实现对临界资源的独占式解决。另外,互斥锁能够解决信号量存在的优先级翻转问题。用互斥锁解决临界资源的同步拜访时,如果有工作拜访该资源,则互斥锁为加锁状态。此时其余工作如果想拜访这个临界资源则会被阻塞,直到互斥锁被持有该锁的工作开释后,其余工作能力从新拜访该公共资源,此时互斥锁再次上锁,如此确保同一时刻只有一个工作正在拜访这个临界资源,保障了临界资源操作的完整性。 本文咱们来一起学习下LiteOS互斥锁模块的源代码,文中所波及的源代码,均能够在LiteOS开源站点https://gitee.com/LiteOS/LiteOS 获取。互斥锁源代码、开发文档,示例程序代码如下: LiteOS内核互斥锁源代码包含互斥锁的公有头文件kernelbaseincludelos_mux_pri.h、头文件kernelincludelos_mux.h、C源代码文件kernelbaselos_mux.c。 开发指南文档–互斥锁在线文档https://gitee.com/LiteOS/Lite... 接下来,咱们看下互斥锁的构造体,互斥锁初始化,互斥锁罕用操作的源代码。 1、互斥锁构造体定义和罕用宏定义1.1 互斥锁构造体定义在文件kernelbaseincludelos_mux_pri.h定义的互斥锁管制块构造体有2个,MuxBaseCB和LosMuxCB,前者和后者的前三个成员一样,能够和pthread_mutex_t共享内核互斥锁机制。构造体源代码如下,构造体成员的解释见正文局部。 typedef struct { LOS_DL_LIST muxList; /**< 互斥锁双向链表 */ LosTaskCB *owner; /**< 以后持有锁的工作 */ UINT16 muxCount; /**< 锁被持有的次数*/} MuxBaseCB;typedef struct { LOS_DL_LIST muxList; /**< 互斥锁双向链表 */ LosTaskCB *owner; /**< 以后持有锁的工作 */ UINT16 muxCount; /**< 锁被持有的次数*/ UINT8 muxStat; /**< 互斥锁状态: OS_MUX_UNUSED, OS_MUX_USED */ UINT32 muxId; /**< 互斥锁Id */} LosMuxCB;1.2 互斥锁罕用宏定义零碎反对创立多少互斥锁是依据开发板状况应用宏LOSCFG_BASE_IPC_MUX_LIMIT定义的,互斥锁Id是UINT32类型的,由2局部组成:count和muxId,别离处于高16位和低16位。创立互斥锁,应用后删除时,互斥锁回收到互斥锁池时,互斥锁Id的高16位即count值会加1,这样能够用来示意该互斥锁被创立删除的次数。muxId取值为[0,LOSCFG_BASE_IPC_MUX_LIMIT),示意互斥锁池中各个的互斥锁的编号。 ⑴处的宏用来宰割count和muxId的位数,⑵处互斥锁被删除时更新互斥锁Id,能够看出高16位为count和低16位为muxId。⑶处获取互斥锁Id的低16位。⑷依据互斥锁Id获取对应的互斥锁被创立删除的次数count。⑸处从互斥锁池中获取指定互斥锁Id对应的互斥锁管制块。 ⑴ #define MUX_SPLIT_BIT 16⑵ #define SET_MUX_ID(count, muxId) (((count) << MUX_SPLIT_BIT) | (muxId))⑶ #define GET_MUX_INDEX(muxId) ((muxId) & ((1U << MUX_SPLIT_BIT) - 1))⑷ #define GET_MUX_COUNT(muxId) ((muxId) >> MUX_SPLIT_BIT)⑸ #define GET_MUX(muxId) (((LosMuxCB *)g_allMux) + GET_MUX_INDEX(muxId))2、互斥锁初始化互斥锁在内核中默认开启,用户能够通过宏LOSCFG_BASE_IPC_MUX进行敞开。开启互斥锁的状况下,在系统启动时,在kernelinitlos_init.c中调用OsMuxInit()进行互斥锁模块初始化。 ...

April 12, 2021 · 5 min · jiezi

关于锁:技术分享-MySQL-行锁超时排查方法优化

作者:xuty本文起源:原创投稿 * 爱可生开源社区出品,原创内容未经受权不得随便应用,转载请分割小编并注明起源。 一、纲要#### 20191219 10:10:10,234 | com.alibaba.druid.filter.logging.Log4jFilter.statementLogError(Log4jFilter.java:152) | ERROR | {conn-10593, pstmt-38675} execute error. update xxx set xxx = ? , xxx = ? where RowGuid = ?com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction之前在如何无效排查解决MySQL行锁期待超时问题 文章中介绍了如何监控解决行锁超时报错,过后介绍的监控计划次要是以 shell 脚本 + general_log 来捕捉行锁期待信息,起初感觉比拟麻烦,因而优化后改成用 Event + Procedure 的办法定时在 MySQl 内执行,将行锁期待信息记录到日志表中,并且退出了 pfs 表中的事务上下文信息,这样能够省去登陆服务器执行脚本与剖析 general_log 的过程,更加便捷。 因为用到了 Event 和 performance_schema 下的零碎表,所以须要关上两者的配置,pfs 应用默认监控项就能够,这里次要应用到的是 events_statements_history 表,默认会保留会话 10 条 SQL。 performance_schema = onevent_scheduler = 1 二、步骤目前该办法仅在 MySQL 5.7 版本应用过,MySQL 8.0 未测试。2.1 创立库create database `innodb_monitor`;2.2 创立存储过程use innodb_monitor;delimiter ;;CREATE PROCEDURE pro_innodb_lock_wait_check()BEGIN declare wait_rows int; set group_concat_max_len = 1024000;CREATE TABLE IF NOT EXISTS `innodb_lock_wait_log` ( `report_time` datetime DEFAULT NULL, `waiting_id` int(11) DEFAULT NULL, `blocking_id` int(11) DEFAULT NULL, `duration` varchar(50) DEFAULT NULL, `state` varchar(50) DEFAULT NULL, `waiting_query` longtext DEFAULT NULL, `blocking_current_query` longtext DEFAULT NULL, `blocking_thd_last_query` longtext, `thread_id` int(11) DEFAULT NULL); select count(*) into wait_rows from information_schema.innodb_lock_waits ; if wait_rows > 0 THEN insert into `innodb_lock_wait_log` SELECT now(),r.trx_mysql_thread_id waiting_id,b.trx_mysql_thread_id blocking_id,concat(timestampdiff(SECOND,r.trx_wait_started,CURRENT_TIMESTAMP()),'s') AS duration, t.processlist_command state,r.trx_query waiting_query,b.trx_query blocking_current_query,group_concat(left(h.sql_text,10000) order by h.TIMER_START DESC SEPARATOR ';\n') As blocking_thd_query_history,thread_id FROM information_schema.innodb_lock_waits w JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id LEFT JOIN performance_schema.threads t on t.processlist_id = b.trx_mysql_thread_id LEFT JOIN performance_schema.events_statements_history h USING(thread_id) group by thread_id,r.trx_id order by r.trx_wait_started; end if;END;;2.3 创立事件事件 每隔 5 秒 (通常等于 innodb_lock_wait_timeout 的值)执行一次,继续监控 7 天,完结后会主动删除事件,也能够自定义保留时长。 ...

February 21, 2021 · 2 min · jiezi

关于锁:理解-Go-的互斥锁

背景在应用 Go 构建 Web 应用程序时,所有传入的 HTTP 申请都会被路由到对应解决逻辑的 Goroutine 中。如果应用程序在解决申请的时候,有读写同一块内存数据, 就存在竞态条件的危险。( Spanner 反对 读写锁定 的事务模式,单个逻辑工夫点以原子形式执行一组读写,不存在竞态条件问题)<!--more--> 数据竞争一个很常见的竞态条件场景就是银行账户余额的读写。思考一种状况,有两个 Goroutine 尝试同时将钱存到同一个银行余额中,例如: 指令Goroutine1Goroutine2银行存款余额1读取余额 <- 500元 500元2 读取余额 <- 500元500元3存入100元,写入银行账号 -> 600元 600元4 存入50元,写入银行账号 -> 550元550元只管进行了两次独自的贷款,但因为第二个 Goroutine 互相对账号余额做更改,因而仅第二笔贷款反映在最终余额中。 这种特定类型的竞态条件称为数据竞争。当两个或多个 Goroutine 尝试同时应用一条共享数据(在此示例中为银行余额)时,它们可能会触发,然而操作后果取决于调度程序执行其指令的程序。 Go 官网博客 也列举了数据竞争导致的一些问题: Race conditions are among the most insidious and elusive programming errors. They typically cause erratic and mysterious failures, often long after the code has been deployed to production. While Go's concurrency mechanisms make it easy to write clean concurrent code, they don't prevent race conditions. Care, diligence, and testing are required.Go 提供了许多工具来帮忙咱们防止数据竞争问题。其中包含用于在 Goroutine 之间进行数据通信的 channel ; 用于在运行时监督对内存的非同步拜访的 Race Detector,以及 Atomic 和 Sync 软件包中的各种“Lock”性能。这些性能之一是互斥锁,咱们将在本文的其余部分中介绍。 ...

October 1, 2020 · 2 min · jiezi

关于锁:java锁机制

锁的作用:在Java中synchronized关键字被罕用于保护数据一致性。 synchronized机制是给共享资源上锁,只有拿到锁的线程才能够访问共享资源,这样就能够强制使得对共享资源的拜访都是程序的。 Java开发人员都意识synchronized,应用它来实现多线程的同步操作是非常简单的,只有在须要同步的对方的办法、类或代码块中退出该关键字,它可能保障在同一个时刻最多只有一个线程执行同一个对象的同步代码,可保障润饰的代码在执行过程中不会被其余线程烦扰。应用synchronized润饰的代码具备原子性和可见性,在须要进程同步的程序中应用的频率十分高,能够满足个别的进程同步要求。 锁的状态: 无锁状态无锁没有对资源进行锁定,所有的线程都能拜访并批改同一个资源,但同时只有一个线程能批改胜利。偏差锁偏是偏心、偏差的意思。当没有线程竞争的时候,偏差于第一个取得这个资源的线程。无竞争的状况下把整个同步都打消掉。轻量级锁无竞争的状况下应用CAS打消同步应用的互斥量。 在代码行将进入同步块的时候,JVM 会在栈空间中开拓一块空间(Lock Record),而后将对象头的Mark Word复制到Lock Record 中。JVM会应用CAS操作尝试将对象的MarkWord更新为指向Lock Record,并且将对象的Mark Word 的锁标记位转变为00,示意以后对象处于轻量级锁定状态。如果这个操作失败了,阐明有其余线程于以后线程竞争,虚构机会首先检测对象的Mark Word是否只想以后线程的栈帧,如果是以后线程曾经领有了这个对象的锁,那么间接进入同步块继续执行,否则阐明这个锁曾经被其余线程占用了,那么会收缩为重量级锁,锁标记位变为10,前面期待锁的线程也必须进入阻塞状态。重量级锁用户态转化为内核态,进入阻塞状态。锁的优化:自旋锁打消锁粗化 锁的降级过程:锁的对象:

September 17, 2020 · 1 min · jiezi

关于锁:iOS之多线程漫谈

前言提到线程,那就不得不提CPU,古代的CPU有一个很重要的个性,就是工夫片,每一个取得CPU的工作只能运行一个工夫片规定的工夫。其实线程对操作系统来说就是一段代码以及运行时数据。操作系统会为每个线程保留相干的数据,当接管到来自CPU的工夫片中断事件时,就会按肯定规定从这些线程中抉择一个,复原它的运行时数据,这样CPU就能够继续执行这个线程了。也就是其实就单核CUP而言,并没有方法实现真正意义上的并发执行,只是CPU疾速地在多条线程之间调度,CPU调度线程的工夫足够快,就造成了多线程并发执行的假象。并且就单核CPU而言多线程能够解决线程阻塞的问题,然而其自身运行效率并没有进步,多CPU的并行运算才真正解决了运行效率问题。零碎中正在运行的每一个应用程序都是一个过程,每个过程零碎都会调配给它独立的内存运行。也就是说,在iOS零碎中中,每一个利用都是一个过程。一个过程的所有工作都在线程中进行,因而每个过程至多要有一个线程,也就是主线程。那多线程其实就是一个过程开启多条线程,让所有工作并发执行。多线程在肯定意义上实现了过程内的资源共享,以及效率的晋升。同时,在肯定水平上绝对独立,它是程序执行流的最小单元,是过程中的一个实体,是执行程序最根本的单元,有本人栈和寄存器。明天要讲的内容1、 iOS中的多线程2、 iOS中的各种线程锁3、 你不得不知的runloop 1.1 PthreadsPOSIX线程(POSIX threads),简称Pthreads,是线程的POSIX规范。该规范定义了创立和操纵线程的一整套API。在类Unix操作系统(Unix、Linux、Mac OS X等)中,都应用Pthreads作为操作系统的线程。 咱们来用Pthreads创立一个线程去执行一个工作: 记得引入头文件`#import "pthread.h"`-(void)pthreadsDoTask{ /* pthread_t:线程指针 pthread_attr_t:线程属性 pthread_mutex_t:互斥对象 pthread_mutexattr_t:互斥属性对象 pthread_cond_t:条件变量 pthread_condattr_t:条件属性对象 pthread_key_t:线程数据键 pthread_rwlock_t:读写锁 // pthread_create():创立一个线程 pthread_exit():终止以后线程 pthread_cancel():中断另外一个线程的运行 pthread_join():阻塞以后的线程,直到另外一个线程运行完结 pthread_attr_init():初始化线程的属性 pthread_attr_setdetachstate():设置脱离状态的属性(决定这个线程在终止时是否能够被联合) pthread_attr_getdetachstate():获取脱离状态的属性 pthread_attr_destroy():删除线程的属性 pthread_kill():向线程发送一个信号 pthread_equal(): 对两个线程的线程标识号进行比拟 pthread_detach(): 拆散线程 pthread_self(): 查问线程本身线程标识号 // *创立线程 int pthread_create(pthread_t _Nullable * _Nonnull __restrict, //指向新建线程标识符的指针 const pthread_attr_t * _Nullable __restrict, //设置线程属性。默认值NULL。 void * _Nullable (* _Nonnull)(void * _Nullable), //该线程运行函数的地址 void * _Nullable __restrict); //运行函数所需的参数 *返回值: *若线程创立胜利,则返回0 *若线程创立失败,则返回出错编号 */ // pthread_t thread = NULL; NSString *params = @"Hello World"; int result = pthread_create(&thread, NULL, threadTask, (__bridge void *)(params)); result == 0 ? NSLog(@"creat thread success") : NSLog(@"creat thread failure"); //设置子线程的状态设置为detached,则该线程运行完结后会主动开释所有资源 pthread_detach(thread);}void *threadTask(void *params) { NSLog(@"%@ - %@", [NSThread currentThread], (__bridge NSString *)(params)); return NULL;}输入后果: ...

August 13, 2020 · 17 min · jiezi

关于锁:java-锁总结

1.基于数据库的乐观锁和乐观锁 有个版本字段,更新的时候先读进去,更新的时候作为where条件update。如果管制版本是状态不是单向的话还是有ABA的问题。单向的没问题。 乐观锁在查问的时候就把数据给锁住。2.基于jdk的乐观锁和乐观锁 synchronized是乐观锁,这种线程一旦失去锁,其余须要锁的线程就挂起的状况就是乐观锁。 CAS操作的就是乐观锁,比拟并替换。每次不加锁而是假如没有抵触而去实现某项操作,如果因为抵触失败就重试,直到胜利为止。这种乐观锁的问题:ABA问题,如果始终再循环对cpu的开销比拟大。不能保障代码块的原子性 CAS机制所保障的只是一个变量的原子性操作,而不能保障整个代码块的原子性。

July 17, 2020 · 1 min · jiezi

技术分享-如何方便的查看-Metadata-Lock

作者:洪斌爱可生南区负责人兼技术服务总监,MySQL  ACE,擅长数据库架构规划、故障诊断、性能优化分析,实践经验丰富,帮助各行业客户解决 MySQL 技术问题,为金融、运营商、互联网等行业客户提供 MySQL 整体解决方案。本文来源:转载自公众号-玩转MySQL*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。MySQL 的 Metadata Lock 机制是为了保护并发访问数据对象的一致性。DDL、表级锁、全局锁都会产生 metadata lock,写操作在锁释放前会被阻塞,而任何会话持有了 metadata lock 在 processlist 中是看不到的。 当发现其他会话被阻塞,就很难快速找到“罪魁祸首”。之前也曾介绍过《快速定位令人头疼的全局锁》。 最近折腾 MySQL shell 插件时发现了一个方法,也能很方便的查询元数据锁。 在社区 MySQL shell 插件库 https://github.com/lefred/mys... 的 ext.check.get_locks() 函数查看实例上锁情况。要在 MySQL 8.0 以上版本,它用到了 CTE 查询。 如果是 MySQL 5.7,需先开启 metadata 的 instrument。 call sys.ps_setup_enable_instrument('wait/lock/metadata/sql/mdl%')执行此 SQL 查看元数据锁情况,上锁会话、SQL、锁类型能关联显示。 SELECT ps.*, lock_summary.lock_summaryFROM sys.processlist ps INNER JOIN ( SELECT owner_thread_id, GROUP_CONCAT( DISTINCT CONCAT( mdl.LOCK_STATUS, ' ', mdl.lock_type, ' on ', IF( mdl.object_type = 'USER LEVEL LOCK', CONCAT(mdl.object_name, ' (user lock)'), CONCAT(mdl.OBJECT_SCHEMA, '.', mdl.OBJECT_NAME) ) ) ORDER BY mdl.object_type ASC, mdl.LOCK_STATUS ASC, mdl.lock_type ASC SEPARATOR '\n' ) as lock_summary FROM performance_schema.metadata_locks mdl GROUP BY owner_thread_id ) lock_summary ON (ps.thd_id = lock_summary.owner_thread_id) \ G ...

June 18, 2020 · 1 min · jiezi