ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

JAVA进阶--锁

2026/8/12 12:13:07 拓冰建站 浏览量
JAVA进阶--锁

Java 中的锁分类

①乐观锁/悲观锁

乐观锁: 就是没有加锁的实现. AtomicInteger(原子类)中的实现就是不加锁的,通过自旋比较实现                (CAS)

悲观锁: 就是加锁的实现,认为不加锁是会出问题的 ,ReentrantLock和synchronized都是悲观锁

可重入锁

ReentrantLock和synchronized都是可重入锁

可重入锁又名递归锁, 指的是一个线程在外层方法获得锁时,可以直接进入到内层的加锁的方法中.

public class Demo {public synchronized void setA(){System.out.println("setA");setB();}private synchronized void setB() {System.out.println("setB");}public static void main(String[] args) {new Demo().setA();}}

    锁对象会记录线程id,当进入到setB时,判断线程id相同则可以进入,两个方法共用同一把锁,当线程进入setA获得锁时,可直接进入到setB方法中,这就是可重入锁

    如果不是可重入锁的话,setB不会 被当前线程执行,造成死锁。

③自旋锁

指的是对synchronized获得锁的一种描述(特点), 线程在获得锁时,是自旋的不断尝试去获得锁

④公平锁/非公平锁

公平锁:  就是排队获得锁,有先来后到  ReentrantLock 既可以是公平锁也可以是非公平锁

非公平锁: 就是抢锁,谁抢到谁执行, 有可能后来的线程先抢到锁  synchronized ReentrantLock

⑤读写锁

ReentrantReadWriteLock

特点: 读读不互斥, 读写互斥, 写写互斥

适合读(查询)多,写少的场景, 提高读的效率

private  int data;//共享数据private ReadWriteLock rwl=new ReentrantReadWriteLock();//写数据public  void set(int data){rwl.writeLock().lock();//取到锁try{System.out.println(Thread.currentThread().getName()+"准备写入数据");this.data=data;System.out.println(Thread.currentThread().getName()+"写入"+this.data);}finally {rwl.writeLock().unlock();//释放锁}}//读数据public  void get(){rwl.readLock().lock();//取到锁try{System.out.println(Thread.currentThread().getName()+"准备读取数据");System.out.println(Thread.currentThread().getName()+"读取"+this.data);}finally {rwl.writeLock().unlock();//释放锁}}

⑥共享锁和独占锁

独占锁: synchronized ReentrantLock都是独占锁,就是有我没他,一次只能有一个线程执行.

共享锁: 一个锁可以被多个线程持有, 读写锁中的读锁就是共享锁

synchronized锁的实现

jdk1.7之后,对synchronized锁进行了优化(jdk7之前synchronized锁没有状态,都是自旋的获取锁),

jdk7之后为synchronized锁设计了不同的状态.

synchronized修饰方法 非静态方法锁对象是this 静态方法是类的Class对象

synchronized修饰代码块

使用synchronized锁的时候,必须为锁提供一个同步锁对象的,此对象就是用来记录锁状态的

对象中有一个区域叫对象头,对象头中有一块区域叫mark word,记录对象运行时的一些数据,如锁状态,哈希值,GC分代年龄,当前线程id.

锁状态

无锁状态: 没有线程进入到同步代码块就是无锁状态

偏向锁状态: 只有一个线程访问同步代码块时,同步锁中记录线程id,下次线程访问时,可以快速的获得锁.

轻量级锁状态: 当线程数量大于1个之后,锁状态由偏向锁升级为轻量级锁, 线程不会阻塞,以自旋方式获得锁,

提高获取锁的效率.

重量级锁状态: 当锁状态为轻量锁时,如果线程自旋到一定次数还获取不到锁,那么锁会升级为重量级锁,让获取不到锁的线程进入到阻塞状态,等待操作系统调度.

AQS

AbstractQueuedSynchronizer 抽象同步队列, 并发包下面很多类的底层实现都会用到

内部有一个int类的变量state,用来记录有没有线程使用

内部会构建一个队列,用来存储没有获得锁的线程

ReentrantLock锁实现

ReentrantLock 基于 AQS的,

ReentrantLock 可以实现公平锁和非公平锁

内部结构:

               ReentrantLock 类内部总共存在Sync、NonfairSync、FairSync 三个类,并且三个内部类是紧密相关的, NonfairSync 与 FairSync 类 继 承 自 Sync 类 , Sync 类 继 承 自AbstractQueuedSynchronizer 抽象类。

公平和非公平的区别:

JUC常用

     Java5.0在java.util.concurrent包中提供了多种并发容器类来改进同步容器的性能。

1.ConcurrentHashMap      

ConcurrentHashMap是一个线程安全的map,加锁的方式与Hashtable不同

Hashtable直接在方法上加锁,一次只能有一个线程进入方法操作.

ConcurrentHashMap不是给方法加的锁,给每个哈希表中的位置加锁

2.CopyOnWriteArrayList 

     ArraayList 是线程不安全的,在高并发情况下可能会出现问题,Vector是线 程安全的。

3.CopyOnWriteArraySet

      CopyOnWriteArraySet 的实现基于CopyOnWriteArrayList,不能存储重复数 据

4.辅助类CountDownLatch

       CountDownLatch 允许一个线程等待其他线程各自执行完毕后再执行。底层实 现实现是通AQS来完成的.创建CountDownLatch对象时指定一个初始值是线 程的数量。每当一个线程执行完毕后,AQS内部的state就-1,当state的值为 0 时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了