12. 面试官不问, 你也不得不知道的锁知识!

面试官:说一下Synchronized底层实现,锁升级的具体过程? 介绍 这是我去年7,8月份面试的时候被问的一个面试题,说实话被问到这个问题还是很意外的,感觉这个东西没啥用啊,直到后面被问了一波new Object,Integer对象等作为加锁对象行吗?会出现哪些问题?为啥java6后synchronized性能大幅上升?我彻底蒙蔽了。下面详细总结一下 synchronized使用方式 我们知道并发编程会产生各种问题的源头是可见性,原子性,有序性。 而synchronized能同时保证可见性,原子性,有序性。所以我们在解决并发问题的时候经常用synchronized,当. 阅读详情

前言

hello, 大家好, 我是咸鱼君, 擅长各种Java摸鱼姿势.

image

恰逢2020年“金九”月,

今天, 我们就来说一说面试中出现频率极高的锁知识!

ps:说不定可以帮到部分有“想法”的同学

image

锁的优化

JDK6开始, synchronized的实现机制进行了较大调整,除了使用JDK5引进的CAS自旋之外, 还增加了以下的优化策略.

  • 自适应的CAS自旋
  • 锁消除
  • 锁粗化
  • 偏向锁
  • 轻量级锁
  • …

这些优化使得synchronized性能获得了极大提高, 所以, 情况允许下, 推荐使用synchronized关键字.

今天, 我们好好了解下synchronized锁进行的那些优化, 这样我们使用时才能清晰的明白优劣, 作出合适的选择.

锁的基本状态

锁主要存在以下四种状态:

  1. 无锁状态
  2. 偏向锁状态
  3. 轻量级锁状态
  4. 重量级锁状态

锁可以从偏向锁 升级到 轻量级锁, 再 升级至 重量级锁.
不过锁的升级是单向的,
也就是说只能从低到高, 不会出现锁的降级.

在 JDK 1.6 中默认是开启偏向锁和轻量级锁的,
可以通过-XX:-UseBiasedLocking来禁用偏向锁.

自旋锁

线程的阻塞和唤醒需要CPU从用户态转为核心态,
频繁的阻塞和唤醒对CPU来说是一件负担很重的工作,势必会给系统的并发性能带来很大的压力.
另外, 其实在许多应用上面, 对象锁的锁状态只会持续很短一段时间,
为了这一段很短的时间频繁地阻塞和唤醒线程是非常不值得的.

所以引入自旋锁.

何谓自旋锁?

所谓自旋锁,
就是指当一个线程尝试获取某个锁时,
如果该锁已被其他线程占用,
就一直循环检测锁是否被释放,
而不是进入线程挂起或睡眠状态.

自旋锁适用于锁保护的临界区很小的情况,
临界区很小的话,锁占用的时间就很短.

自旋等待不能替代阻塞,
虽然它可以避免线程切换带来的开销, 但是它占用了CPU处理器的时间.
如果持有锁的线程很快就释放了锁,那么自旋的效率就非常好,
反之,自旋的线程就会白白消耗掉处理的资源,它不会做任何有意义的工作,典型的占着茅坑不拉屎,这样反而会带来性能上的浪费.

所以说,自旋等待的时间(自旋的次数)必须要有一个限度,
如果自旋超过了定义的时间仍然没有获取到锁,则应该被挂起.

自旋锁在JDK 1.4.2中引入,默认关闭,但是可以使用
-XX:+UseSpinning开启,
在JDK1.6中默认开启. 同时自旋的默认次数为10次,可以通过参数-XX:PreBlockSpin来调整.

如果通过参数**-XX:PreBlockSpin**来调整自旋锁的自旋次数,会带来诸多不便.
假如将参数调整为10,
但是系统很多线程都是等你刚刚退出的时候就释放了锁(假如多自旋一两次就可以获取锁),是不是很尴尬.
于是JDK1.6引入自适应的自旋锁,让虚拟机会变得越来越聪明.

适应性自旋锁

JDK 1.6引入了更加聪明的自旋锁,即自适应自旋锁.
所谓自适应就意味着自旋的次数不再是固定的,它是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定.

那它如何进行适应性自旋呢?

线程如果自旋成功了,
那么下次自旋的次数会更加多,因为虚拟机认为既然上次成功了,
那么此次自旋也很有可能会再次成功,那么它就会允许自旋等待持续的次数更多.

反之,如果对于某个锁,很少有自旋能够成功,
那么在以后要或者这个锁的时候自旋的次数会减少甚至省略掉自旋过程,
以免浪费处理器资源.

有了自适应自旋锁, 随着程序运行和性能监控信息的不断完善,
虚拟机对程序锁的状况预测会越来越准确, 虚拟机会变得越来越聪明.

锁消除

为了保证数据的完整性,
在进行操作时需要对部分操作进行同步控制,
但是在有些情况下,JVM检测到不可能存在共享数据竞争,
此时, JVM会对这些同步锁进行锁消除.

锁消除的依据是逃逸分析的数据支持

逃逸分析

逃逸分析的是一个对象的动态作用域,2种情况
方法逃逸:对象通过参数传递传给了另一个方法
线程逃逸:对象有另外的线程访问
逃逸分析的目的是确认一个对象是否只可能当前线程能访问

如果不存在竞争,为什么还需要加锁呢?
所以, 锁消除可以节省毫无意义的请求锁的时间.

变量是否逃逸,对于虚拟机来说需要使用数据流分析来确定的,
对于开发人员来说, 一些情况是可以主观分析出来的,
比如,不存在数据竞争的代码块不需要加上同步!

但是, 有时候程序并不是我们所想的那样,
虽然没有显示使用锁, 但是在使用一些JDK的内置API时,如

  • StringBuffer
  • Vector
  • HashTable
  • 其它…

这个时候会存在隐形的加锁操作.

比如StringBuffer的append()方法, Vector的add()方法:

public void vectorTest(){
    Vector<String> vector = new Vector<String>();
    for(int i = 0 ; i < 10 ; i++){
        vector.add(i + "");
    }
    System.out.println(vector);
}

在运行这段代码时,
JVM可以明显检测到变量vector没有逃逸出vectorTest()方法外,
所以JVM可以大胆地将vector内部的加锁操作消除.

锁粗化

锁粗化概念比较好理解,就是将多个连续的加锁、解锁操作连接在一起,扩展成一个范围更大的锁

为什么要锁粗化?

在使用同步锁的时候, 需要让同步块的作用范围尽可能小(仅在共享数据的实际作用域中才进行同步).
这样做是为了使需要同步的操作数量尽可能缩小,如果存在锁竞争,那么等待锁的线程也能尽快拿到锁.

在大多数的情况下,上述观点是正确的.

但是, 如果一系列的连续加锁解锁操作,可能会导致不必要的性能损耗,
所以引入锁粗化的概念.

还举个上文中的例子

public void vectorTest(){
    Vector<String> vector = new Vector<String>();
    for(int i = 0 ; i < 10 ; i++){
        vector.add(i + "");
    }
    System.out.println(vector);
}

vector每次add的时候都需要加锁操作,
JVM检测到对同一个对象(vector)连续加锁、解锁操作, 会合并一个更大范围的加锁、解锁操作, 即加锁解锁操作会移到for循环之外.

偏向锁

偏向锁是JDK6中引入的重要概念.
HotSpot虚拟机作者经过研究实践发现,
在大多数情况下, 锁不仅不存在多线程竞争, 而且总是由同一线程多次获得;
为了让线程获得锁的代价更低, 所以引进了偏向锁.

偏向锁是在单线程执行代码块时使用的机制.
如果在多线程并发的环境下(即线程A尚未执行完同步代码块,线程B发起了申请锁的申请),则一定会转化为轻量级锁或者重量级锁.

在JDK5中, 偏向锁默认是关闭的;
而到了JDK6中, 偏向锁已经默认开启.
如果并发数较大,并且同步代码块执行时间较长时,
则被多个线程同时访问的概率就很大,
此时就可以使用参数-XX:-UseBiasedLocking来禁止偏向锁(但这是个JVM参数,不能针对某个对象锁来单独设置).

引入偏向锁主要目的:

为了在没有多线程竞争的情况下,
尽量减少不必要的轻量级锁执行路径.
因为轻量级锁的加锁解锁操作是需要依赖多次CAS原子指令的;
而偏向锁只需要在置换ThreadID的时候依赖一次CAS原子指令(由于一旦出现多线程竞争的情况就必须撤销偏向锁,所以偏向锁的撤销操作的性能损耗也必须小于节省下来的CAS原子指令的性能消耗).

轻量级锁是为了在线程交替执行同步块时提高性能;
而偏向锁则是在只有一个线程执行同步块时进一步提高性能.

那么偏向锁是如何来减少不必要的CAS操作呢?

首先我们看下无竞争下锁存在什么问题:

现在几乎所有的锁都是可重入的,即已经获得锁的线程可以多次锁住/解锁监视对象;
按照HotSpot之前的设计,
每次加锁/解锁都会涉及到一些CAS操作(比如对等待队列的CAS操作),
CAS操作会延迟本地调用,

因此偏向锁的想法是:
一旦线程第一次获得了监视对象,
之后让监视对象“偏向”这个线程,
之后的多次调用则可以避免CAS操作;
说白了就是置个变量,
如果发现为true则无需再走各种加锁/解锁流程.

CAS为什么会引入本地延迟?

这要从SMP(对称多处理器)架构说起,下图大概表明了SMP的结构:

SMP(对称多处理器)架构

如图, 所有的CPU会共享一条系统总线(BUS),靠此总线连接主存.
每个核心都有自己的一级缓存,各核相对于BUS对称分布,
因此这种结构称为“对称多处理器”.

而CAS的全称为Compare-And-Swap,是一条CPU的原子指令;
其作用是让CPU比较后, 原子地更新某个位置的值;
其实现方式是基于硬件平台的汇编指令,
也就是说CAS是靠硬件实现的,JVM只是封装了汇编调用;
那些AtomicInteger类便是使用了这些封装后的接口.

举个例子

两个核心,Core1和Core2,
Core1和Core2可能会同时把主存中某个位置的值Load到自己的L1 Cache中,
当Core1在自己的L1 Cache中修改这个位置的值时,会通过总线,使Core2中L1 Cache对应的值“失效”;
而Core2一旦发现自己L1 Cache中的值失效(称为Cache命中缺失)则会通过总线从内存中加载该地址最新的值;
大家通过总线的来回通信称为“Cache一致性流量”,
因为总线被设计为固定的“通信能力”,
如果Cache一致性流量过大,总线将成为瓶颈.
而当Core1和Core2中的值再次一致时,称为“Cache一致性”;
从这个层面来说,锁设计的终极目标便是减少Cache一致性流量.

而CAS恰好会导致Cache一致性流量,
如果有很多线程都共享同一个对象,
当某个Core CAS成功时必然会引起总线风暴,
这就是所谓的本地延迟,
本质上偏向锁就是为了消除CAS,降低Cache一致性流量.

Cache一致性:

上面提到Cache一致性,其实是有协议支持的,现在通用的协议是MESI(最早由Intel开始支持),具体参考:http://en.wikipedia.org/wiki/MESI_protocol.

Cache一致性流量的例外情况:

其实也不是所有的CAS都会导致总线风暴,这跟Cache一致性协议有关,具体参考:http://blogs.oracle.com/dave/entry/biased_locking_in_hotspot

NUMA(Non Uniform Memory Access Achitecture)架构:

与SMP对应还有非对称多处理器架构,现在主要应用在一些高端处理器上;
主要特点是:

  • 没有总线;
  • 没有公用主存;
  • 每个Core有自己的内存;

针对这种结构此处不做讨论.

所以,当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程进入和退出同步块时不需要花费CAS操作来争夺锁资源,只需要检查是否为偏向锁、锁标识为以及ThreadID即可,处理流程如下:

  1. 检测Mark Word是否为可偏向状态,即是否为偏向锁1,锁标识位为01;
  2. 若为可偏向状态,则测试线程ID是否为当前线程ID,如果是,则执行步骤(5),否则执行步骤(3);
  3. 如果测试线程ID不为当前线程ID,则通过CAS操作竞争锁,竞争成功,则将Mark Word的线程ID替换为当前线程ID,否则执行线程(4);
  4. 通过CAS竞争锁失败,证明当前存在多线程竞争情况,当到达全局安全点,获得偏向锁的线程被挂起,偏向锁升级为轻量级锁,然后被阻塞在安全点的线程继续往下执行同步代码块;
  5. 执行同步代码块;

偏向锁的释放采用了 一种只有竞争才会释放锁的机制,线程是不会主动去释放偏向锁,需要等待其他线程来竞争.偏向锁的撤销需要 等待全局安全点(这个时间点是上没有正在执行的代码).其步骤如下:

1.暂停拥有偏向锁的线程;
2. 判断锁对象是否还处于被锁定状态,否,则恢复到无锁状态(01),以允许其余线程竞争.是,则挂起持有锁的当前线程,并将指向当前线程的锁记录地址的指针放入对象头Mark Word,升级为轻量级锁状态(00),然后恢复持有锁的当前线程,进入轻量级锁的竞争模式;

注意:此处将 当前线程挂起再恢复的过程中并没有发生锁的转移,仍然在当前线程手中,只是穿插了个 “将对象头中的线程ID变更为指向锁记录地址的指针” 这么个事.

偏向锁的获取和释放过程

轻量级锁

引入轻量级锁的主要目的是 在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗.当关闭偏向锁功能或者多个线程竞争偏向锁导致偏向锁升级为轻量级锁,则会尝试获取轻量级锁,其步骤如下:

  1. 在线程进入同步块时,如果同步对象锁状态为无锁状态(锁标志位为“01”状态,是否为偏向锁为“0”),虚拟机首先将在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储锁对象目前的Mark Word的拷贝,官方称之为 Displaced Mark Word.此时线程堆栈与对象头的状态如下图所示:
    轻量级锁CAS操作之前线程堆栈与对象的状态

  2. 拷贝对象头中的Mark Word复制到锁记录(Lock Record)中;

  3. 拷贝成功后,虚拟机将使用CAS操作尝试将对象Mark Word中的Lock Word更新为指向当前线程Lock Record的指针,并将Lock record里的owner指针指向object mark word.如果更新成功,则执行步骤(4),否则执行步骤(5);

  4. 如果这个更新动作成功了,那么当前线程就拥有了该对象的锁,并且对象Mark Word的锁标志位设置为“00”,即表示此对象处于轻量级锁定状态,此时线程堆栈与对象头的状态如下图所示:
    轻量级锁CAS操作之后线程堆栈与对象的状态

  5. 如果这个更新操作失败了,虚拟机首先会检查对象Mark Word中的Lock Word是否指向当前线程的栈帧,如果是,就说明当前线程已经拥有了这个对象的锁,那就可以直接进入同步块继续执行.否则说明多个线程竞争锁,进入自旋执行(3),若自旋结束时仍未获得锁,轻量级锁就要膨胀为重量级锁,锁标志的状态值变为“10”,Mark Word中存储的就是指向重量级锁(互斥量)的指针,当前线程以及后面等待锁的线程也要进入阻塞状态.

轻量级锁的释放也是通过CAS操作来进行的,主要步骤如下:

1.通过CAS操作尝试把线程中复制的Displaced Mark Word对象替换当前的Mark Word;
2.如果替换成功,整个同步过程就完成了,恢复到无锁状态(01);
3. 如果替换失败,说明有其他线程尝试过获取该锁(此时锁已膨胀),那就要在释放锁的同时,唤醒被挂起的线程;

对于轻量级锁,其性能提升的依据是 “对于绝大部分的锁,在整个生命周期内都是不会存在竞争的”,如果打破这个依据则除了互斥的开销外,还有额外的CAS操作,因此在有多线程竞争的情况下,轻量级锁比重量级锁更慢.

轻量级锁的获取和释放过程

  1. 为什么升级为轻量锁时要把对象头里的Mark Word复制到线程栈的锁记录中呢?

因为在申请对象锁时 需要以该值作为CAS的比较条件,同时在升级到重量级锁的时候,能通过这个比较判定是否在持有锁的过程中此锁被其他线程申请过,如果被其他线程申请了,则在释放锁的时候要唤醒被挂起的线程.

  1. 为什么会尝试CAS不成功以及什么情况下会不成功?

CAS本身是不带锁机制的,其是通过比较而来.假设如下场景:线程A和线程B都在对象头里的锁标识为无锁状态进入,那么如线程A先更新对象头为其锁记录指针成功之后,线程B再用CAS去更新,就会发现此时的对象头已经不是其操作前的对象HashCode了,所以CAS会失败.也就是说,只有两个线程并发申请锁的时候会发生CAS失败.

然后线程B进行CAS自旋,等待对象头的锁标识重新变回无锁状态或对象头内容等于对象HashCode(因为这是线程B做CAS操作前的值),这也就意味着线程A执行结束(参见后面轻量级锁的撤销,只有线程A执行完毕撤销锁了才会重置对象头),此时线程B的CAS操作终于成功了,于是线程B获得了锁以及执行同步代码的权限.如果线程A的执行时间较长,线程B经过若干次CAS时钟没有成功,则锁膨胀为重量级锁,即线程B被挂起阻塞、等待重新调度.

此处,如何理解“轻量级”?“轻量级”是相对于使用操作系统互斥量来实现的传统锁而言的.但是,首先需要强调一点的是,轻量级锁并不是用来代替重量级锁的,它的本意是在没有多线程竞争的前提下,减少传统的重量级锁使用产生的性能消耗.

轻量级锁所适应的场景是线程交替执行同步块的情况,如果存在同一时间访问同一锁的情况,必然就会导致轻量级锁膨胀为重量级锁.

重量级锁

Synchronized是通过对象内部的一个叫做 监视器锁(Monitor)来实现的.但是监视器锁本质又是依赖于底层的操作系统的Mutex Lock来实现的.而操作系统实现线程之间的切换这就需要从用户态转换到核心态,这个成本非常高,状态之间的转换需要相对比较长的时间,这就是为什么Synchronized效率低的原因.因此,这种依赖于操作系统Mutex Lock所实现的锁我们称之为 “重量级锁”.

重量级锁、轻量级锁和偏向锁之间转换

重量级锁、轻量级锁和偏向锁之间转换

Synchronized偏向锁、轻量级锁及重量级锁转换流程

锁的优劣

各种锁并不是相互代替的,而是在不同场景下的不同选择,绝对不是说重量级锁就是不合适的.每种锁是只能升级,不能降级,即由偏向锁->轻量级锁->重量级锁,而这个过程就是开销逐渐加大的过程.

  1. 如果是单线程使用,那偏向锁毫无疑问代价最小,并且它就能解决问题,连CAS都不用做,仅仅在内存中比较下对象头就可以了;
  2. 如果出现了其他线程竞争,则偏向锁就会升级为轻量级锁;
  3. 如果其他线程通过一定次数的CAS尝试没有成功,则进入重量级锁;

在第3种情况下进入同步代码块就 要做偏向锁建立、偏向锁撤销、轻量级锁建立、升级到重量级锁,最终还是得靠重量级锁来解决问题,那这样的代价就比直接用重量级锁要大不少了.所以使用哪种技术,一定要看其所处的环境及场景,在绝大多数的情况下,偏向锁是有效的,这是基于HotSpot作者发现的“大多数锁只会由同一线程并发申请”的经验规律.

锁的优劣

参考文章: 源码架构

都看到这了, 不点个“赞”就想跑?

image

欢迎关注我

技术公众号 “CTO技术”

订阅号.png

面试官:MySQL中InnoDB行锁变表锁的原因可能有哪些? 从设计之初,就应该建立良好的索引机制,避免对关键字段搜索时造成表锁」「避免长时间事务未提交等情况,导致锁冲突,死锁等情况」「不要老是抱怨数据库有问题,应该从自身写的 SQL 分析出发,学会分析(数据库不行大部分是因为 SQL 写的有问题,没错,是自身问题)」「不要总是觉得这是 DBA 该做的事,开发者应该学会基本的 SQL 常识(如 MySQL 的最左索引,回表,索引覆盖等知识),学会基本的优化步骤。 阅读详情

相关推荐

从零开始:kohya_ss环境部署与LoRA/SDXL模型训练实战指南

本文提供了一份详细的kohya_ss环境部署与模型训练实战指南。从零开始,手把手教你使用Conda创建虚拟环境、安装依赖并启动Web GUI界面。核心内容涵盖高质量数据集的准备方法,并重点解析了如何使用kohya_ss工具进行LoRA模型和SDXL模型的微调训练,包括关键参数配置与常见报错解决方案,帮助初学者快速上手AI绘画模型定制。

weixin_29162439的博客 534

内部锁之一:锁介绍(偏向锁 & 轻量级锁 & 重量级锁 & 各自优缺点及场景)

一、内部锁介绍   上篇文章《Synchronized之二:synchronized的实现原理》中向大家介绍了Synchronized原理及优化锁。现在我们应该知道,Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的。但是监视器锁本质又是依赖于底层的操作系统的Mutex Lock来实现的。而操作系统实现线程之间的切换这就需要从用户态转换到核心态,这个成...

weixin_34149796的博客 435

5种主流触觉传感器对比:GelSight、DIGIT、Taxim、GelSlim和TACTO如何选?

本文深度解析了GelSight、DIGIT、Taxim、GelSlim和TACTO五款主流触觉传感器的技术原理与核心特性。通过对比视觉传感与电学传感两大技术路径,为机器人灵巧抓取、精密检测等应用场景提供清晰的选型决策指南,帮助开发者根据项目需求在分辨率、响应速度、集成度与成本之间找到最佳平衡。

Black的专栏 929

JVM内部细节之二:偏向锁(Biased Locking)

在前面一片文章《JVM内部细节之一:synchronized关键字及实现细节》中已经提到过偏向锁的概念,在理解什么是偏向锁前必须先理解什么是轻量级锁(Lightweight Locking)。引入偏向锁是为了在无多线程竞争的情况下尽量减少不必要的轻量级锁执行路径,因为轻量级锁的获取及释放依赖多次CAS原子指令,而偏向锁只需要在置换ThreadID的时候依赖一次CAS原子指令(由于一旦出现多线...

weixin_30757793的博客 645

从零玩转GD32单片机CAN总线:手把手实战配置与源码解析

本文提供了一份基于GD32单片机的CAN总线实战入门指南。从硬件连接(GD32F103C8T6与TJA1050收发器)到软件配置,详细解析了CAN初始化、波特率计算、过滤器设置及中断收发等核心源码。通过手把手的回环测试示例与常见问题排查,帮助开发者快速掌握CAN总线通信的关键配置与调试技巧。

g5h6i7j的博客 481

OpenClaw Docker 安装问题解决全记录

控制面板无法加载(WebSocket 错误) | 确认 Nginx 配置中的 `Upgrade` 和 `Connection` 头正确 || 网关容器无法启动 | `docker compose logs openclaw-gateway`,检查权限、镜像名 |如需消除,使用 Let's Encrypt |- `<your-token>`:你的 OpenClaw 网关令牌(如 `b0e5ab...`)将 `<nas-ip>` 替换为你的群晖内网 IP(例如 `192.168.1.100`)。

u014490376的博客 2308

深入JVM锁机制1-synchronized

JVM锁,synchronized,Lock,自选锁,偏向锁,Cache一致性,Cache一致性流量,SMP

老码农的专栏 4万+

【学长笔记】关于车牌识别的CCPD数据集按比例划分

本文介绍了一个用于CCPD车牌数据集划分的Python脚本,主要功能包括:1) 将数据集按比例划分为训练集、验证集和测试集;2) 支持图像与标签文件校验;3) 可自定义划分比例和样本数量限制;4) 自动生成标准目录结构。脚本使用随机种子确保可重复性,并通过tqdm显示进度条。处理后数据可直接用于YOLO等目标检测模型的训练与评估,建议在预处理完成后立即执行划分以避免数据泄露。文章还提供了相关技术博客的参考链接。

apple_53308981的博客 1472

一文搞懂锁知识

一位风尘仆仆的男子走了过来,对我说:小伙子,我看你简历上写的精通mysql,那我就问问你mysql的知识吧! 我:好的(千万别多问,千万别多问~~) 面试官:对mysql锁了解的多吗? 我:还行(其实就是很好)。 面试官:那好,那我接下来主要问锁相关的知识 我:好的好的(放马过来吧,我也就是客气一下。) 面试官: mysql支持哪些级别的锁? 我:支持库锁、表锁、行锁。 面试官:那先说说库锁吧,锁库有几种方式? 我:两种,分别是FTWRL(Flush tables with read

假装懂编程的博客 9453

手把手教你用Kali Linux搭建vulntarget-a靶场环境(附详细配置步骤)

本文详细介绍了如何在Kali Linux环境下搭建vulntarget漏洞靶场,包括环境规划、虚拟化平台配置、靶机系统部署及安全工具链配置等关键步骤。通过实战演练,帮助网络安全从业者和初学者掌握专业级漏洞实验平台的搭建与管理技巧,提升安全测试能力。

weixin_29279101的博客 107

【花雕学编程】Arduino ESP32 SPP 之使用Servo库控制360度舵机正反转

使用 Servo 库控制 360 度舵机的正反转是 Arduino ESP32 SPP 应用中的一个重要案例,具有简易控制接口、灵活速度调节和高兼容性等特点,广泛应用于机器人、自动化装置和动态艺术等领域。在第三个案例中,使用map()函数将用户输入的速度参数(范围0-100)映射到舵机控制的角度(0-180),使得用户能够以更人性化的方式控制舵机速度。5、创新:Arduino可以让你用电子的方式来表达你的创意和想象,你可以用Arduino来制作各种有趣和有用的项目,如机器人、智能家居、艺术装置等。

雕爷学编程 1468

【面试官】知道synchronized锁升级吗

线程A获取了某个对象锁,但在线程代码的流程中仍需再次获取该对象锁,此时线程A可以继续执行不需要重新再获取该对象锁。既然获取锁的粒度是线程,意味着线程自己是可以获取自己的内部锁的,而如果获取锁的粒度是调用则每次经过同步代码块都需要重新获取锁。此时synchronized重量级锁就回归到了悲观锁的状态,其他获取不到锁的都会进入阻塞状态。来获得锁,CAS操作不需要获得锁、释放锁,减少了像synchronized重量级锁带来的。轻量级锁通过CAS自旋来获得锁,如果自旋10次失败,为了减少CPU的消耗则锁会膨胀为。

JavaSouth南哥 3275

YOLO11全网首发:CVPR2026 MixerCSeg | DEGConv方向引导边缘门控,破解细长裂缝检测难题

DEGConv通过方向先验嵌入、边缘增强卷积和动态门控三大机制,针对性解决了YOLO在处理裂缝类细长、多方向、低对比度目标时的特征提取不足问题,显著提升了裂缝检测的精度与鲁棒性。

①答疑群聊服务;②YOLO大模型知识问答系统;③计算机视觉论文生成智能体; 560

与面试官的一次促膝长谈:人家也是第一次当面试官,你们答不上来我也特别尴尬!

面试官到底是何方神圣?相信对于很多校招、实习萌新一直都不清楚屏幕另一端的面试官到底是怎么样一个人?是打分机器?技术大牛?还是……本文便是博主从各个面试官那里挖来的面试猛料,带你直击面试官内心世界,让你更好地与面试官对话!

Stay Hungry Stay Foolish 求知若饥 虚心若愚 7421

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

面试官的潜台词你知道哪些?

面试潜台词解码:150字摘要 面试官的问题往往暗藏玄机。"自我介绍"实则是考察岗位匹配度;"住哪里"意在评估稳定性;"为什么离职"切忌吐槽前公司。公司"画饼"话术需警惕:"成长空间大"可能意味着低薪,"晋升快"可能是人手不足。福利描述也有门道:"弹性工作制"常变相加班,"提供食宿"可能地处偏远。回答技巧上,要正向积极、聚焦职业发展,用"追求

KanS1的博客 3271

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

面试命中率90%!面试官:你知道MySQL锁吗?

锁分类 当多个事务或进程访问同一个资源时,为了保证数据的一致性就会用到锁机制,在MySQL中锁有多种不同的分类。 以操作粒度区分 行级锁、表级锁和页级锁 表级锁:每次操作锁住整张表。锁定的粒度大、开销小、加锁快;不会发生死锁,但发生锁冲突的概率极高,并发度最低,应用在InnoDB、MyISAM、BDB中; 行级锁:每次操作锁住一行数据。锁定的粒度小、开销大、加锁慢;会出现死锁,发生锁冲突的概率极低,并发度最高,应用在InnoDB中; 页级锁:每次锁定相邻的一组记录。锁定粒度、开销、加锁时间介于行

公众号:该用户快成仙了 2216

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

面试官:Zookeeper集群怎么搭建?

zookeeper集群你会搭建吗?

真正的大师永远怀着一颗学徒的心 5679

程序员:我终于知道Java这些“锁”事了

作者:千珏 邮箱:wl625363199@gmail.com 文章目录前言悲观锁和乐观锁自旋锁和适应性自旋锁无锁和偏向锁和轻量级锁和重量级锁公平锁和非公平锁可重入锁和非可重入锁独享锁和共享锁总结 前言 每次面试的时候总是有面试官会甩出致命三连 高并发、高可用、高性能 我们又称其为程序员三高,今天千珏本珏讲的就是三高中的高并发中的“锁”事。 首先我们要知道java中要有哪些锁,下面这张图千珏认...

zjwl199802的博客 3174

lock是乐观锁吗_面试官:聊聊你知道的锁

开篇思考你知道哪些锁?锁解决了哪些应用场景的问题?锁的底层实现?java 中的并发包了解吗?CAS 会有哪些问题?如何解决?AQS 是并发包的基础,实现原理是什么?synchronize 是可重入锁吗?如果上面的思考题都能直接准确回答,直接去面试吧。锁1. 悲观锁并不是某一个锁,是一个锁类型,无论是否并发竞争资源,都会锁住资源,并等待资源释放下一个线程才能获取到锁。这明显很悲观,所以就叫悲观锁。这...

weixin_36393718的博客 2050

面试官:小伙子知道synchronized的优化过程吗?我:嘚吧嘚吧嘚,面试官:出去!

会联想的同学,我想已经猜出了大概,首先在Java中的锁都是基于对象的,既然基于对象,那它存在的地方大概率要在对象中,而我们知道在JVM中,对象分为三个部分对象头、实例数据、字节对齐,其中对象头又由Mark Word和Klass Point构成,而Mark Word(标记字段)用于存储对象自身的运行时数据,例如存储对象的HashCode,分代年龄、锁标志位等信息,是synchronized实现轻量级锁和偏向锁的关键。5️⃣进入重量级锁的状态,这个时候,自旋的线程进行阻塞,等待之前线程执行完成并唤醒自己。

JavaBuild的博客 963

面试官:JVM对锁进行了优化,都优化了啥?

从JDK1.6开始,JVM对锁进行了各种优化,目的就是为了在线程间更高效的共享数据和解决互斥同步的问题。从锁优化的话题开始,可以引申出很多考点面试题,比如锁优化的技术、各优化技术的细节、CAS实现原理、CAS的ABA问题及如何解决等,持续发散还会引发更多问题,例如逃逸分析等,可以看出技术点都是相关联的,需要不断积累和梳理。面试官:JVM实现了哪些锁优化技术?小白:自旋锁、自适应自旋锁、锁粗化、锁消...

JavaQ 1113

面试官:说一下公平锁和非公平锁的区别?

前言 上次我们提到了乐观锁和悲观锁,那我们知道锁的类型还有很多种,我们今天简单聊一下,公平锁和非公平锁两口子,以及他们在我们代码中的实践。 正文 开始聊之前,我先大概说一下他们两者的定义,帮大家回顾或者认识一下。 公平锁:多个线程按照申请锁的顺序去获得锁,线程会直接进入队列去排队,永远都是队列的第一位才能得到锁。 优点:所有的线程都能得到资源,不会饿死在队列中。 缺点:吞吐量会下降很多...

CharlesYooSky的博客 3709

Java最新面试命中率90%!面试官:你知道MySQL锁吗?,java中级面试宝典

即使是面试跳槽,那也是一个学习的过程。只有全面的复习,才能让我们更好的充实自己,武装自己,为自己的面试之路不再坎坷!今天就给大家分享一个Github上全面的Java面试题大全,就是这份面试大全助我拿下大厂Offer,月薪提至30K!我也是第一时间分享出来给大家,希望可以帮助大家都能去往自己心仪的大厂!为金三银四做准备!

a19815156的博客 1050

java 线程的锁 通俗_面试官:聊聊你知道的锁

开篇思考你知道哪些锁?锁解决了哪些应用场景的问题?锁的底层实现?java 中的并发包了解吗?CAS 会有哪些问题?如何解决?AQS 是并发包的基础,实现原理是什么?synchronize 是可重入锁吗?如果上面的思考题都能直接准确回答,直接去面试吧。锁1. 悲观锁并不是某一个锁,是一个锁类型,无论是否并发竞争资源,都会锁住资源,并等待资源释放下一个线程才能获取到锁。这明显很悲观,所以就叫悲观锁。这...

weixin_36222664的博客 219

看看我给面试官是如何娓娓道来synchronized锁升级过程的

知乎高赞,看看我给面试官是如何娓娓道来synchronized锁升级过程的!!!

Java框架、并发编程、分布式、微服务、Redis、HarmonyOS、中间件等技术 1415
上一篇: 11. 嗨, 需要谈个对象…………?
下一篇: 42. 从零开始学springboot整合alibaba-nacos做注册/配置中心
码哥说
博客等级 码龄8年 5645粉丝 172原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码哥说

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值