写点什么

2021-06-05# Java 基础 (dayFourteen):锁的两种方式

  • 2021 年 11 月 10 日
  • 本文字数:1418 字

    阅读完需:约 5 分钟


并发同步




当两个或两个以上的线程需要共享对同一数据的存取或修改时,会发生覆盖现象,覆盖情况取决于线程调度器先调度哪一个线程,这种情况通常称为竞态条件

锁对象

Java 提供两种机制防止并发访问代码块


  1. Synchronized 关键字

  2. ReentrantLock 类

ReentrantLock

使用 ReentrantLock 来进行加锁的话,都是要用在 try 语句上(即 lock 方法后面必须紧跟 try 语句),最后一定要用 finally 来释放锁



该结构确保了在任何时刻只有一个线程可以进入下面的 lock 后的语句块里面,也就是临界区


一旦一个线程锁定了锁对象,其他任何线程都无法通过 lock 语句,当其他线程调用 lock 时,则会进行暂停,直到前面的线程释放这个锁对象,也就是 unlock


举个栗子


下面是某类加锁的方法



测试的 main 方法


![在这里插入图片描述](https://img-blog.csdnimg.cn/20210605232013800.png?x-oss-process=image/watermark,type_ZmFu


【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


Z3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0dEVVRfVHJpbQ==,size_16,color_FFFFFF,t_70#pic_center)


结果为



可以看到在 lock 前面的代码是可以让其他线程执行的,但是 lock 后面的代码必须等待前面的线程释放锁才可以去执行,期间就会发生阻塞


这里要注意的是,每个对象会有自己的 ReentrantLock,所以要争抢同一个 ReentrantLock 对象才会发生阻塞,该锁就可以保证串行化访问,如果是两个不同的对象,以上个栗子为例,就是两个不同的 TestSyncFunny 对象,那么两个线程得到的是不同的锁,是不会发生阻塞现象的


这个锁称为重入锁(ReentrantLock:重入),因为这个锁可以被线程反复获得,该锁会有一个持有计数来跟踪对 lock 方法的嵌套使用,即在加锁的 try 语句块里面调用方法 A,该方法 A 加的是同一把锁(同一个 ReentranLock),所以获得 B 的锁也会去影响 A 的运行


举个栗子


private ReentrantLock lock = new ReentrantLock();


public void doSyncTo(String name){


System.out.println("下面"+name+"也要进行加锁");


lock.lock();


try{


System.out.println(name+"已经加锁了~~~~");


Thread.sleep(2000);


} catch (InterruptedException e) {


e.printStackTrace();


} finally {


lock.unlock();


}


}


public void doSync(String name){


System.out.println(name+"还没进行上锁----");


lock.lock();


try{


System.out.println(name + "上锁了,dododoodid");


doSyncTo(name);


System.out.println(name+"调用完了另一个加锁方法,并且已经释放那个锁了");


Thread.sleep(2000);


System.out.println(name+"睡醒了");


//code....


} catch (InterruptedException e) {


e.printStackTrace();


} finally {


lock.unlock();


}


}


上面是两个加锁的方法,用都是同一个 ReentrantLock,而且在 doSync 方法中,还调用了 doSyncTo 的方法



可以看到,调用 doSync 拿到的 ReentrantLock,会让其他线程也无法调用 doSyncTo 加锁后的那些方法,必须要等线程释放了最外的一层锁,即 doSync 的 lock 才可以调用,单独释放了 doSyncTo 里面的 lock 也是不够的

公平锁

我们也可以使用 ReentrantLock 来构建一个公平锁


调用下面的构造方法,传入 true 参数



公平锁是指:锁释放的时候,倾向于让等待时间最长的线程获取该锁


不过公平锁会影响性能,所以一般情况下都是非公平的,而且公平锁不一定是绝对公平的,还要取决于线程调度器,如果线程调度器忽略了一个已经为锁等待很长时间的线程,那就不能实现公平

评论

发布
暂无评论
2021-06-05# Java基础(dayFourteen):锁的两种方式