第一篇CSDN的博文,java中的锁问题

   

目录

0.锁

1.死锁

1.1.3如何检查死锁

2.悲观锁

3.乐观锁

4.自旋锁

5.可重入锁

6.偏向锁

7.轻量级锁

8.重量级锁


    第一篇博文,看csdn很久了,心血来潮写一写,当做一个电子笔,也可以和大家分享,方便自己持续积累和回顾,也希望有什么不足大家多多指正,千里之行始于足下,希望自己可以坚持下去,也希望我们都能在编程的路上一路向前,坚持下去,加油~

        第一篇就从Java中的锁问题开始吧:

0.锁

0.1说明

在记录这篇笔记的时候,我突然发现,既然这篇笔记记录的是关于锁的问题,那么我有必要聊一下什么是锁,以及为什么会使用到锁

0.2什么是锁,为什么使用锁

我们知道锁一般应用在多线程中,并且,在我们学习java多线程的时候明确的知道多线程会发生线程安全问题,多线程的安全问题一般是什么呢,在多线程中,如果我们对同一个共享资源进行操作,可能会由于时间片切换而对一个对象进行多次操作

举个例子:我们指定多线程的执行流程为:

执行判断操作(多线程执行的条件,可能是对象数量是否为空等等,视业务而定)->按照业务执行多线程操作

假设A线程在抢占时间片之后,执行了判断操作,并确定可以执行,但是这时候时间片到期了,这个线程进入等待队列,于是线程B抢占了时间片,线程B执行了判断操作,可以执行,并执行了业务操作,然后时间片到期,这是A线程又抢占到了时间片,并按照上次时间片前的顺序继续执行业务操作;最终导致的结果是两个线程对一个共享资源执行了两次操作,但实际资源并不存在这么多,这样就导致了多线程安全问题

那么我们是不是可以做这样一个设定,当A线程在切换时间片的时候,我们对这个资源做一个标记,表示这个资源是A线程抢占但是未执行完的操作,那么当其他线程抢占到时间片之后,就不会对这个共享资源进行操作,而是去寻找其他的共享资源,当A线程重新抢占时间片之后,对比标记,确定A线程身份,并接着执行这个未完成的操作,就可以避免多线程的安全问题,这种操作就是程序中的锁.

因此,锁其实是在并发下控制多个操作的执行顺序,以此来保证数据安全的变动

1.死锁

在正式的进行锁的介绍之前,我们有必要认识一下死锁,并尽量在开发中避免死锁的产生

1.1什么是死锁,和为什么会产生死锁

在多线程开发中,当两个或者多个线程互相占有一些资源,并互相等待其他线程释放资源而形成的一种僵局,就叫做死锁

举个例子:线程A需要a和b资源来运行,线程B也需要a和b资源运行,A线程占有a资源,B线程占有b资源,他们都在等待对方释放资源来完成己方操作,这种因为相互等待而出现的僵持现象就是死锁

1.2死锁发生的场景

 public class Test {
 
    public static void main(String[] args) {
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                synchronized (B.class) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (A.class) {
                        
                    }
                }
            }
        }).start();
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                synchronized (A.class) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    synchronized (B.class) {
                        
                    }
                }
                
            }
        }).start();
    }
    
}
class A {
    
}
 
class B {
    
}

死锁一般发生在一个线程嵌套一个线程的时候,并且他们同时需要a和b资源来运行

死锁是我们在开发中应该避免的情况

1.1.3如何检查死锁

死锁是我们在开发中应该避免的情况,但是我们不可能永远都保证我们不会遇到死锁问题,那么如何查看死锁发生在 哪里呢,在java中为我们提供了一个Jconsole工具来帮助我们查看死锁.这个工具目前我没有用过,并且没有一个场景来让我模拟解决死锁问题,

2.悲观锁

2.1什么是悲观锁

悲观锁总是做最坏的打算,每次别人去拿数据的时候,都认为别人会修改数据,因此他对每一次操作都加上了锁,这样如果别人想拿到这个数据,只能等待加锁的这个人执行完成并释放锁,别人才可以对这个数据加锁并进行其他操作

悲观锁是一个重量级的锁,他会降低程序效率

2.2悲观锁被用在哪里

在传统的关系型数据库中使用了很多的悲观锁,如按照使用性质划分的读锁和写锁,以及按照作用范围划分的行锁和表锁

(我们在后面具体介绍读锁和写锁,一级行锁和表锁)

同时我们熟知的sychronized就是一个悲观锁,jdk对sychronized做了一个优化(下面分析)

3.乐观锁

3.1什么是乐观锁

乐观锁总是最最好的打算,认为不论进行什么操作,别人都不会修改数据,但是在更新期间会去判断是否有人更新这个数据,并做后续处理

乐观锁在本质上相当于没有加锁,他是通过cas算法来实现的(后面介绍),所以乐观锁的效率会比较高

4.自旋锁

4.1什么是自旋锁

自旋锁就是在在尝试获取锁的过程中,不会立即阻塞,而是通过循环的方式不断的尝试来获取锁

自旋锁是有自旋时间的,超过自旋时间就会进入阻塞状态

为什么使用自旋锁,因为线程的唤醒和阻塞都是需要 时间的,当我们能够很快再次获取时间片的时候,为了节省时间资源就可以使用自旋锁

4.2优缺点

好处:线程不会立刻(自旋锁有一个最大时间,超时还是会进入阻塞状态)进入阻塞状态,减少了线程上下文之间的切换

坏处:增加了cpu的消耗

实际使用要根据实际情况来使用

不可重入锁又叫自旋锁吗??????好像确实是这样

用处:

如果锁的颗粒小,那么所得持有时间比较短(尽管具体的持有时间无法得知,但可以认为,通常有一部分锁能满足上述特性),那么锁阻塞造成的线程切换的时间与锁持有的时间相当,减少线程阻塞造成的线程切换,可以获得较大的性能提升

4.3自适应自旋锁

自适应自旋锁意味着自旋时间不在是一个固定值,而是由上一次在同一个锁上的自选时间及锁的拥有者的状态来决定的

自适应自旋锁解决的是"锁竞争时间不确定"的问题

缺点:自适应自旋锁也没能彻底解决锁竞争时间不确定的问题,如果默认的自旋次数设置不合理(过高或过低),那么自适应的过程将很难收敛到合适的值

5.可重入锁

5.1什么是可重入锁

没搞明白

但是sychronized锁就是一种可重入锁

6.偏向锁

6.1什么是偏向锁

按照我的理解,如果不仅仅没有实际竞争,自始至终,使用锁的线程只有一个,那么维护轻量级锁都是浪费的,偏向锁的目标是,减少无竞争且只有一个线程使用锁的情况下,使用轻量级锁产生的性能消耗

6.2缺点

当明显存在其他线程申请锁,那么偏向锁将会很快膨胀为轻量级锁

7.轻量级锁

7.1什么是轻量级锁

如果没有完全实际的锁竞争(什么是没有实际的锁竞争),那么申请重量级锁都是浪费的,轻量级锁的目标是:减少无实际竞争情况下,使用重量级锁产生的的性能消耗,包括系统调用引起的内核态与用户态切换,线程阻塞造成的线程切换

7.2缺点

如果锁竞争激烈,那么轻量级锁很快就会膨胀成重量级锁,那么位置轻量级锁的过程就成了浪费,还不如在开始的时候直接使用重量级锁

8.重量级锁

8.1什么是重量级锁

在jdk1.6之前,监视器锁可以认为直接对应底层操作系统之间的互斥量,这种同步方式的成本非常高,包括系统调用硬气的内核态与用户态切换,线程阻塞造成的线程切换等,因此,后来这种锁被称为重量级锁

        

        

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值