java之Java锁(二)

多线程加锁

  • Synchronized
  • 显式Lock

Synchronized

关键字,只要在代码块(方法)添加关键字synchronized,即可以实现同步的功能
本质上是一种互斥锁,Java中每个对象都有一个内置锁(监视器,也可以理解成锁标记),而synchronized就是使用**对象的内置锁(监视器)**来将代码块(方法)锁定的!即锁的使用以对象为单位,一个对象被锁住后,其他线程无法使用该对象内部的代码

  • 修饰普通方法,用的锁是本对象(内置锁)
  • 修饰代码块用的锁是括号内obj(内置锁)
  • 修饰静态方法,用的锁是类对象的
重入锁
public class Widget {
    // 锁住了
    public synchronized void doSomething() {
        ...
    }
}

public class LoggingWidget extends Widget {
    // 锁住了
    public synchronized void doSomething() {
        System.out.println(toString() + ": calling doSomething");
        super.doSomething();
    }
}
  1. 当线程A进入到LoggingWidget的doSomething()方法时,此时拿到了LoggingWidget实例对象的锁。
  2. 随后在方法上又调用了父类Widget的doSomething()方法,它又是被synchronized修饰。
  3. 那现在我们LoggingWidget实例对象的锁还没有释放,进入父类Widget的doSomething()方法还需要一把锁吗?
    不需要的!
    显而易见,一个线程不能自己死锁自己。

因为锁的持有者是“线程”,针对于实例对象,而不是“调用”。线程A已经是有了LoggingWidget实例对象的锁了,当再需要的时候可以继续“开锁”进去的!

这就是内置锁的可重入性

lock显式锁

与内置锁的区别

  • Lock方式来获取锁支持中断、超时不获取、是非阻塞的
  • 提高了语义化,哪里加锁,哪里解锁都得写出来
  • Lock显式锁可以给我们带来很好的灵活性,但同时我们必须手动释放锁
  • 支持Condition条件对象
  • 允许多个读线程同时访问共享资源
    我们绝大部分时候还是会使用Synchronized锁
公平锁

公平锁理解起来非常简单:

线程将按照它们发出请求的顺序来获取锁
非公平锁就是:

线程发出请求的时可以“插队”获取锁
Lock和synchronize都是默认使用非公平锁的。如果不是必要的情况下,不要使用公平锁

公平锁会来带一些性能的消耗的

AQS

juc是什么?
juc就是一个包:java.util.concurrent
该包下的locks包内部三个抽象类:

  • AbstractOwnableSynchronizer
  • AbstractQueuedLongSynchronizer
  • AbstractQueuedSynchronizer
    通常AbstractQueueSynchronizer简称为AQS
    Lock之类的两个常见的锁都是基于它来实现的
  • AQS其实就是一个可以给我们实现锁的框架
  • 内部实现的关键是:先进先出的队列、state状态
  • 定义了内部类ConditionObject
  • 拥有两种线程模式
    • 独占模式
    • 共享模式
  • 在LOCK包中的相关锁(常用的有ReentrantLock、 ReadWriteLock)都是基于AQS来构建
  • 一般我们叫AQS为同步器
同步状态

使用volatile修饰实现线程可见性,使用CAS实现原子操作

acquire方法

用于实现lock方法
acquire(int)尝试获取资源,如果获取失败,将线程插入等待队列。插入等待队列后,acquire(int)并没有放弃获取资源,而是根据前置节点状态状态判断是否应该继续获取资源,如果前置节点是头结点,继续尝试获取资源,如果前置节点是SIGNAL状态,就中断当前线程,否则继续尝试获取资源。直到当前线程被park()或者获取到资源,acquire(int)结束。

release方法

用于实现unlock方法
首先调用子类的tryRelease()方法释放锁,然后唤醒后继节点,在唤醒的过程中,需要判断后继节点是否满足情况,如果后继节点不为且不是作废状态,则唤醒这个后继节点,否则从tail节点向前寻找合适的节点,如果找到,则唤醒.

Lock锁子类

最常用的两个子类:

  • ReentrantLock
  • ReentrantReadWriteLock
ReentrantLock
  • 跟synchronized具有相同的功能和语义(互斥锁),但更加灵活
  • isHeldByCurrentThread和getHoldCount判断当前线程是否有锁
  • 支持设置公平锁(相对公平)
  • 应在try代码块之前去调用lock并在finally中unlock
ReentrantReadWriteLock

读写锁,读锁允许多线程进入临界区,写锁为互斥锁

  • 读锁不支持条件对象,写锁支持条件对象
  • 读锁不能升级为写锁,写锁可以降级为读锁
  • 读写锁也有公平和非公平模式
  • 读锁支持多个读线程进入临界区,写锁是互斥的

内部类 ReadLock和WriteLock

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值