锁机制的学习

锁机制

锁的产生

  1. 锁会涉及线程安全问题,线程安全就是线程最终运行的结果和预想一样就是安全的,否则就是线程不安全的
  2. 解决线程安全的方式
    1. 不跨线程共享变量,线程共享的变量改为方法局部级变量
    2. 使状态变量为不可变的,使用final修饰(将变量变为常量)
    3. 在任何访问状态变量的时候,使用同步,使用synchronized修饰方法,或者使用同步代码块
    4. 每个共享的可变变量由唯一一个确定的锁保护,使用Lock锁
  3. 锁是一种保护机制,在多线程的情况下,保证数据操作的一致性

锁的分类

  1. 悲观锁,乐观锁,可重入锁,自旋锁,独享锁,读写锁,阻塞锁,公平锁,非公平锁,分段锁,对象锁,类锁,轻量级锁,分布式锁等
  2. 悲观锁:对外界的修改持保守态度,在整个数据处理中,将数据处于锁定状态,悲观锁适用于读少写多的情况
  3. 乐观锁:和悲观锁相反,假设数据一般情况下不会造成冲突,只有在数据进行提交更新时,才会正式对数据的冲突与否进行检测,如果冲突了,则返回错误信息,让用户决定如何去做,一共分为三个阶段:数据读取,写入校验,数据写入,乐观锁适用于读多写少的场景,这样可以提高系统的并发量
  4. 可重入锁:也叫递归锁,在同一个线程在调用外层方法获取锁的时候,再进入内层方法会自动获取锁,ReentrantLock和synchronized都是可重入锁,可重入锁的一个好处就是可一定程度上避免死锁
  5. 自旋锁:采用让当前线程不停地在循环体内执行,当循环的条件被其他线程改变时才能进入临界区。自旋锁只是将当前线程不停地执行循环体,不进行线程状态的改变,所以响应速度更快,但当线程数不断增加时,性能下降明显,因为每个线程都需要执行,会占用CPU时间片,如果线程竞争不激烈,并保持锁的时间段,适合使用自旋锁
  6. 独享锁:该锁一次只能被一个线程所持有,ReentrantLock,Synchronized都是独享锁
  7. 共享锁:锁可被多个线程持有,ReentrantReadWriteLock,其读锁是共享锁,写锁是独享锁,读锁的共享锁可以保证并发性是非常高效的,读写,写读,写写的过程都是互斥的,独享锁和共享锁也是通过AQS(AbstractQueuedSynchronizer)实现的,通过实现不同的方法,来实现独享或共享
  8. 互斥锁/读写锁:独享锁/共享锁是一种广义的说法,互斥锁/读写锁是具体的实现,互斥锁在java中的具体实现就是ReentrantLock读写锁在java中的具体实现就是ReentrantReadWriteLock
  9. 阻塞锁:可以说是让线程进入阻塞状态进行等待,当获得相应的信号(唤醒,时间)时,才可以进入线程的准备就绪状态,准备就绪状态的所有线程,通过竞争,进入运行状态,java中,能够进入/退出,阻塞状态或包含阻塞锁的方法有:synchronized关键字,ReentrantLock,Object.wait()/notify(),LockSupport()/unpark()
  10. 公平锁:多个线程按照申请锁的顺序来获取锁
  11. 非公平锁:多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁,可能造成优先级反转或饥饿现象,对于java ReentrantLock而言,通过构造函数ReentrantLock(boolean fair)指定该锁是否是公平锁,默认是非公平锁,非公平锁的优点在于吞吐量比公平锁大,对于synchronized来说,也是一种非公平锁
  12. 分段锁:其实是一种锁的设计,目的是细化锁的粒度,并不是具体的一种锁,对于ConcurrentHashMap而言,其并发的实现就是通过分段锁的形式来实现高效的并发操作,ConcurrentHashMap中的分段锁称为Segment,即类似与HashMap(jdk1.7)的结构,内部拥有一个Entry数组,数组中的每个元素是一个链表,同时又是一个ReentrantLock(Segment继承了ReentrantLock),当需要put元素的时候,并不是对整个HashMap加锁,而是先通过hashcode知道要放在哪个分段中,然后对这个分段加锁,所以当多线程put时,只要不是放在一个分段中,可支持并行插入
  13. 对象锁:一个线程可以多次对同一个对象上锁,对于每个对象,java虚拟机维护一个加锁计数器,线程每获得一次该对象,计数器就加1,每释放一次,计数器就减1,当计算器为0时,锁就完全被释放了,
    在java中程序中,只需要使用synchronized块或synchronized方法就可以标志一个监控区域,当每次进入一个监视区域时,java虚拟机会自动锁上对象或类;
    synchronized修饰非静态方法,同步代码块的synchronized(this),synchronized(非this对象),锁的是对象,线程想要执行对应同步代码,需要获得对象锁
  14. 类锁:synchronized修饰静态方法或同步代码块的synchronized(类.class),线程想要执行对应同步代码,需要获得类锁
  15. 分布式锁:分布式集群中,对锁接口QPS性能要求很高,单台服务器满足不了要求,可以考虑将锁服务部署在独立的分布式系统中,比如借助分布式缓存来实现,工作中分布式锁可以使用Redis或ZooKeeper来完成
  16. 补充
    1. CAS机制:乐观锁设计基础
    2. 死锁:互相持有对方的锁的情况就会产生死锁
    3. AQS:AbstractQueuedSynchronizer,提供了一套实现阻塞锁和一系列依赖FIFO等待同步器的理论基础,ReentrantLock,Semaphore,CountDownLatch,CyclicBarrier等并发类均是基于AQS来实现的,具体用法是通过继承AQS实现其模板方法,然后将子类作为同步组件的内部类
    4. QPS query per second,每秒请求数,服务器在一秒的时间内处理了多少个请求,计算方式采用日志统计,可以通过埋点或计算web服务器的access log,一般通过access log统计
    5. 计算QPS的方式
      1. 打印时间,利用日志处理来打印
      2. Tomcat NGINX包含访问日志 access.log
        多态服务器:计算QPS时,需要注意的是负载均衡的策略
        NGINX负载均衡策略:
        随机轮询
        权重weight = 9; weight = 1
        根据URL取hash值,所有的访问某个URL都指向同一台服务器,web服务端缓存(不是redis)
        根据IP(客户端访问IP)取hash值,
        响应优先,多劳多得
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

狠情

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

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

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

打赏作者

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

抵扣说明:

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

余额充值