并发编程中,锁是经常需要用到的,今天我们一起来看下Java中的锁机制:synchronized和lock。

Synchronized 和 Lock的概念

Synchronized 是Java 并发编程中很重要的关键字,另外一个很重要的是 volatile。Syncronized 的目的是一次只允许一个线程进入由他修饰的代码段,从而允许他们进行自我保护。Synchronized 很像生活中的锁例子,进入由Synchronized 保护的代码区首先需要获取 Synchronized 这把锁,其他线程想要执行必须进行等待。Synchronized 锁住的代码区域执行完成后需要把锁归还,也就是释放锁,这样才能够让其他线程使用。

Lock 是 Java并发编程中很重要的一个接口,它要比 Synchronized 关键字更能直译"锁"的概念,Lock需要手动加锁和手动解锁,一般通过 lock.lock() 方法来进行加锁, 通过 lock.unlock() 方法进行解锁。与 Lock 关联密切的锁有 ReetrantLock 和 ReadWriteLock。

ReetrantLock 实现了Lock接口,它是一个可重入锁,内部定义了公平锁与非公平锁。

ReadWriteLock 一个用来获取读锁,一个用来获取写锁。也就是说将文件的读写操作分开,分成2个锁来分配给线程,从而使得多个线程可以同时进行读操作。ReentrantReadWirteLock实现了ReadWirteLock接口,并未实现Lock接口。

Synchronized 和 Lock 的使用

Synchronized 和 Lock 的使用:

下面是 Synchronized 的例子:

在方法上使用 Synchronized

方法声明时使用,放在范围操作符之后,返回类型声明之前。即一次只能有一个线程进入该方法,其他线程要想在此时调用该方法,只能排队等候。

private int number;
public synchronized void numIncrease(){number++;
}

在某个代码段使用 Synchronized

你也可以在某个代码块上使用 Synchronized 关键字,表示只能有一个线程进入某个代码段。

public void numDecrease(Object num){synchronized (num){number++;}
}

使用 Synchronized 锁住整个对象

synchronized后面括号里是一对象,此时线程获得的是对象锁。

public void test() {synchronized (this) {// ...}
}

下面是 Lock 的例子:

Lock是一个接口,它主要由下面这几个方法

public interface Lock {void lock();void lockInterruptibly() throws InterruptedException;boolean tryLock();boolean tryLock(long time, TimeUnit unit) throws InterruptedException;void unlock();Condition newCondition();
}

对上面 Lock 接口的方法做一个简单的解释:

lock(): lock 方法可能是平常使用最多的一个方法,就是用来获取锁。如果锁被其他线程获取,则进行等待。

如果采用Lock,必须主动去释放锁,并且在发生异常时,不会自动释放锁。

Lock lock = ...;
lock.lock();
try{//处理任务
}catch(Exception ex){}finally{lock.unlock();   //释放锁
}

tryLock() :方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。

tryLock(long time, TimeUnit unit) 方法和tryLock()方法是类似的,只不过区别在于这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。

Lock lock = ...;
if(lock.tryLock()) {try{//处理任务}catch(Exception ex){}finally{lock.unlock();   //释放锁}
}else {//如果不能获取锁,则直接做其他事情
}

lockInterruptibly() : 此方法比较特殊,当通过这个方法去获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。也就是说,当两个线程同时通过 lock.lockInterruptibly() 想获取某个锁时,假若此时线程A获取到了锁,而线程B只有在等待,那么对线程B调用 threadB.interrupt() 方法能够中断线程B的等待过程。

由于 lockInterruptibly() 的声明中抛出了异常,所以 lock.lockInterruptibly() 必须放在try块中或者在调用lockInterruptibly() 的方法外声明抛出 InterruptedException。一般形式如下:

public void method() throws InterruptedException {lock.lockInterruptibly();try {//.....}finally {lock.unlock();}
}

一般来说,使用Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,以保证锁一定被被释放,防止死锁的发生。

注意,当一个线程获取了锁之后,是不会被interrupt()方法中断的。因为本身在前面的文章中讲过单独调用interrupt()方法不能中断正在运行过程中的线程,只能中断阻塞过程中的线程。因此当通过lockInterruptibly()方法获取某个锁时,如果不能获取到,只有进行等待的情况下,是可以响应中断的。而用synchronized修饰的话,当一个线程处于等待某个锁的状态,是无法被中断的,只有一直等待下去。

Synchronized 和 Lock 的主要区别

Synchronzied 和 Lock 的主要区别如下:

  • 存在层面:Syncronized 是Java 中的一个关键字,存在于 JVM 层面,Lock 是 Java 中的一个接口

  • 锁的释放条件:1. 获取锁的线程执行完同步代码后,自动释放;2. 线程发生异常时,JVM会让线程释放锁;Lock 必须在 finally 关键字中释放锁,不然容易造成线程死锁

  • 锁的获取: 在 Syncronized 中,假设线程 A 获得锁,B 线程等待。如果 A 发生阻塞,那么 B 会一直等待。在 Lock 中,会分情况而定,Lock 中有尝试获取锁的方法,如果尝试获取到锁,则不用一直等待

  • 锁的状态:Synchronized 无法判断锁的状态,Lock 则可以判断

  • 锁的类型:Synchronized 是可重入,不可中断,非公平锁;Lock 锁则是 可重入,可判断,可公平锁

  • 锁的性能:Synchronized 适用于少量同步的情况下,性能开销比较大。Lock 锁适用于大量同步阶段:

    • Lock 锁可以提高多个线程进行读的效率(使用 readWriteLock)

    • 在竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态;

    • ReetrantLock 提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。

Synchronized 和 Lock 的区别和使用场景相关推荐

  1. Synchronized与Lock的区别与应用场景

    同步代码块,同步方法,或者是用java提供的锁机制,我们可以实现对共享资源变量的同步控制. 技术点: 1.线程与进程: 在开始之前先把进程与线程进行区分一下,一个程序最少需要一个进程,而一个进程最少需 ...

  2. synchronized与Lock的区别与使用

    原文链接 https://blog.csdn.net/u012403290/article/details/64910926 ###引言: 昨天在学习别人分享的面试经验时,看到Lock的使用.想起自己 ...

  3. 题目:三个售票员 卖出 30张票 || 多线程编程的企业级套路+模板||synchronized与Lock的区别

    package com.dym.juc;//资源类 class Ticket {private int number =30;public synchronized void saleTicket() ...

  4. Java多线程之Synchronized和Lock的区别

    Java多线程之Synchronized和Lock的区别 目录: 原始构成 使用方法 等待是否可以中断 加锁是否公平 锁绑定多个条件Condition 小结:Lock相比较Synchronized的优 ...

  5. Java之多线程里面的锁理解以及synchronized与Lock的区别

    一.宏观的说下锁的分类 1)锁分为乐观锁.悲观锁 悲观锁认为对于同一个数据的并发操作,一定是会发生修改的,哪怕没有修改,也会认为修改.因此对于同一个数据的并发操作,悲观锁采取加锁的形式.悲观的认为,不 ...

  6. synchronized与lock的区别总结

    前言 在项目开发中经常会用到锁,synchronized与lock是经常在开发中使用到的.在面试中也会问道这两个的使用区别和原理.这里就梳理总结一下. synchronized与lock的区别 1.l ...

  7. 详解synchronized与Lock的区别与使用

    ###引言: 昨天在学习别人分享的面试经验时,看到Lock的使用.想起自己在上次面试也遇到了synchronized与Lock的区别与使用.于是,我整理了两者的区别和使用情况,同时,对synchron ...

  8. Java中synchronized和Lock的区别

    前言 最近有一个需求是需要将数据库的一些数据抽取出来放到文件文件命名方式为"FILENAME_yyyyMMddHHmmss",例如FILENAME_20200625120011.计 ...

  9. 【Java】synchronized与lock的区别

    从Java 5之后,在java.util.concurrent.locks包下提供了另外一种方式来实现同步访问,那就是Lock. 也许有朋友会问,既然都可以通过synchronized来实现同步访问了 ...

最新文章

  1. flink和kafka区别_Apache Flink和Kafka入门
  2. php实现把es6转为es5,使用webpack将ES6转化ES5的实现方法
  3. POJ 2777 线段树
  4. mpvue 小程序 页面unLoad后数据没清空
  5. 大鱼吃豆子游戏java_java swing开发简单的大鱼吃豆子小游戏,可用于毕业设计(附详细设计文档)...
  6. c语言输入1显示good,求助 无论输入什么输出的结果是个0
  7. Echarts数据可视化series-bar柱形图详解,开发全解+完美注释
  8. 分享Silverlight/WPF/Windows Phone一周学习导读(8月22日-8月27日)
  9. 【python游戏编程之旅】第一篇---初识pygame
  10. msfconsole攻击ftp_MSFconsole核心命令教程
  11. 【刘润五分钟商学院】156对对抗思考到平行思考
  12. 2018小米商城首页html,html+css实现小米商城首页静态页面
  13. 使用SecOC打造的CAN网络依旧很不安全
  14. php怎么分栏,word文档怎么设置分栏格式
  15. docker进入容器中的方法
  16. 解读工业互联网建设中的安全保障
  17. tcp短连接TIME_WAIT问题解决方法大全(1)——高屋建瓴
  18. XP计算机桌面锁定进不去,[xp系统开机进不了桌面]启动进不去桌面上,电脑开机进不去桌面上怎么解决...
  19. 数字加减与摄氏华氏度转化 王明哲
  20. 计算机硬盘空间不足怎么删,电脑d盘的空间不足怎么办_电脑怎么清空d盘-win7之家...

热门文章

  1. go语言学习路线图_2019年最新Go语言学习路线图,三个月带你通关Go语言
  2. RecyclerView——实现短视频布局
  3. 树莓派编程控制继电器及继电器组
  4. ubuntu linux 启动日志,如何在Ubuntu 18.04 LTS上查看系统日志文件
  5. Spark 3.0 Dynamic Partition Pruning 动态裁剪分区
  6. 鸢尾花数据集可视化分析
  7. 探索性数据分析(Exploratory Data Analysis,EDA)
  8. 一年中最后一个月的最后一天说说_月底月末最后一天说说心情语句 一个月又过了感...
  9. 网页设计作业花甲美食网站设计——精美花甲美食网页(8页) 海鲜网页制作作业 生鲜水果蔬菜网页设计模板 简单学生网页设计代做 静态HTML CSS网站制作成品
  10. Leetcode-How-What 力扣Leetcode刷题指南