Java Lock机制解读

欢迎转载: https://blog.csdn.net/chengyuqiang/article/details/79181229

1、synchronized

synchronized是Java语言内置的特性,用来实现对资源的同步访问以及用wait和notify来实现线程间通信。如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁。
存在问题:那么如果这个获取锁的线程由于要等待IO或者其他原因(比如调用sleep方法)被阻塞了,但是又没有释放锁,其他线程便只能干巴巴地等待,试想一下,这多么影响程序执行效率。因此我们需要不论程序的代码块执行的如何最终都将锁对象进行释放,方便其他线程的执行。

2、引入Lock

虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,同时为了更好地释放锁,为了更清晰的表达如何加锁和释放锁,从Java5开始提供了一个新的锁对象Lock。

java.util.concurrent.locks包为锁和等待条件提供一个框架的接口和类,结构如下图所示。

(1)Lock和ReadWriteLock是两大锁根接口,Lock代表实现类是ReentrantLock(可重入锁),ReadWriteLock(读写锁)的代表实现类是ReentrantReadWriteLock。

  • Lock 接口支持那些语义不同(重入、公平等)的锁规则,可以在非阻塞式结构的上下文(包括 hand-over-hand 和锁重排算法)中使用这些规则。主要的实现是 ReentrantLock。
  • ReadWriteLock 接口以类似方式定义了一些读取者可以共享而写入者独占的锁。此包只提供了一个实现,即 ReentrantReadWriteLock,因为它适用于大部分的标准用法上下文。但程序员可以创建自己的、适用于非标准要求的实现。

(2)Condition 接口描述了可能会与锁有关联的条件变量。这些变量在用法上与使用 Object.wait
访问的隐式监视器类似,但提供了更强大的功能。需要特别指出的是,单个 Lock 可能与多个 Condition
对象关联。为了避免兼容性问题,Condition 方法的名称与对应的 Object 版本中的不同。

3、Lock解读

Lock接口有6个方法

// 获取锁
void lock() // 如果当前线程未被中断,则获取锁
void lockInterruptibly() // 返回绑定到此 Lock 实例的新 Condition 实例
Condition newCondition() // 仅在调用时锁为空闲状态才获取该锁
boolean tryLock() // 如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁
boolean tryLock(long time, TimeUnit unit) // 释放锁
void unlock()
 

其中 lock与 unlock是最常用的方法,分别是获取与释放锁。

【例子1】Lock锁

package demo;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockThread {
Lock lock = new ReentrantLock();
public void lock(String name) {
// 获取锁
lock.lock();
try {
System.out.println(name + " get the lock");
// 访问此锁保护的资源
} finally {
// 释放锁
lock.unlock();
System.out.println(name + " release the lock");
}
} public static void main(String[] args) {
LockThread lt = new LockThread();
new Thread(() -> lt.lock("A")).start();
new Thread(() -> lt.lock("B")).start();
}
}


从执行结果可以看出,A线程和B线程同时对资源加锁,A线程获取锁之后,B线程只好等待,直到A线程释放锁B线程才获得锁。

总结一下,也就是说Lock提供了比synchronized更多的功能。但是要注意以下几点:

1)synchronized是Java语言的关键字,因此是内置特性,Lock不是Java语言内置的,Lock是一个接口,通过实现类可以实现同步访问。

2)synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中

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

4、ReadWriteLock解读

ReadWriteLock 接口只有两个方法:

//返回用于读取操作的锁
Lock readLock()
//返回用于写入操作的锁
Lock writeLock()

ReadWriteLock 维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。只要没有 writer,读取锁可以由多个 reader 线程同时保持,而写入锁是独占的。

【例子】三个线程同时对一个共享数据进行读写

package demo;

import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; class Queue {
//共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。
private Object data = null; ReadWriteLock lock = new ReentrantReadWriteLock(); // 读数据
public void get() {
// 加读锁
lock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " be ready to read data!");
Thread.sleep((long) (Math.random() * 1000));
System.out.println(Thread.currentThread().getName() + " have read data :" + data);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放读锁
lock.readLock().unlock();
}
} // 写数据
public void put(Object data) {
// 加写锁
lock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " be ready to write data!");
Thread.sleep((long) (Math.random() * 1000));
this.data = data;
System.out.println(Thread.currentThread().getName() + " have write data: " + data);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放写锁
lock.writeLock().unlock();
} }
} public class ReadWriteLockDemo {
public static void main(String[] args) {
final Queue queue = new Queue();
//一共启动6个线程,3个读线程,3个写线程
for (int i = 0; i < 3; i++) {
//启动1个读线程
new Thread() {
public void run() {
while (true) {
queue.get();
}
} }.start();
//启动1个写线程
new Thread() {
public void run() {
while (true) {
queue.put(new Random().nextInt(10000));
}
}
}.start();
}
}
}

执行结果

Thread-0 be ready to read data!
Thread-2 be ready to read data!
Thread-4 be ready to read data!
Thread-2 have read data :null
Thread-0 have read data :null
Thread-4 have read data :null
Thread-5 be ready to write data!
Thread-5 have write data: 3872
Thread-1 be ready to write data!
Thread-1 have write data: 4744
Thread-3 be ready to write data!
Thread-3 have write data: 1371
Thread-2 be ready to read data!
Thread-0 be ready to read data!
Thread-4 be ready to read data!
Thread-2 have read data :1371
Thread-0 have read data :1371
Thread-4 have read data :1371
Thread-5 be ready to write data!
Thread-5 have write data: 2874
Thread-5 be ready to write data!
Thread-5 have write data: 389
Thread-5 be ready to write data!
Thread-5 have write data: 2512
Thread-5 be ready to write data!
Thread-5 have write data: 7455
Thread-5 be ready to write data!
Thread-5 have write data: 5141
Thread-5 be ready to write data!
Thread-5 have write data: 7709
Thread-1 be ready to write data!
Thread-1 have write data: 7670
Thread-1 be ready to write data!
Thread-1 have write data: 7144
Thread-1 be ready to write data!
Thread-1 have write data: 5673
Thread-1 be ready to write data!
Thread-1 have write data: 7810
Thread-1 be ready to write data!
Thread-1 have write data: 3937
Thread-3 be ready to write data!
Thread-3 have write data: 4259
Thread-2 be ready to read data!
Thread-0 be ready to read data!
Thread-4 be ready to read data!
Thread-0 have read data :4259
Thread-2 have read data :4259
Thread-4 have read data :4259
Thread-5 be ready to write data!
Thread-5 have write data: 9939
Thread-5 be ready to write data! .....
 

转载:Java Lock机制解读的更多相关文章

  1. (转载)Java反射机制

    Java反射机制是Java语言被视为准动态语言的关键性质.Java反射机制的核心就是允许在运行时通过Java Reflection APIs来取得已知名字的class类的相关信息,动态地生成此类,并调 ...

  2. [转载]Java 反射机制(包括组成、结构、示例说明等内容)

    FROM:http://www.cnblogs.com/skywang12345/p/3345205.html 第1部分 Java 反射机制介绍 Java 反射机制.通俗来讲呢,就是在运行状态中,我们 ...

  3. Java回调机制解读

    模块间调用 在一个应用系统中,无论使用何种语言开发,必然存在模块之间的调用,调用的方式分为几种: (1)同步调用 同步调用是最基本并且最简单的一种调用方式,类A的方法a()调用类B的方法b(),一直等 ...

  4. Java回调机制总结

    调用和回调机制 在一个应用系统中, 无论使用何种语言开发, 必然存在模块之间的调用, 调用的方式分为几种: 1.同步调用 同步调用是最基本并且最简单的一种调用方式, 类A的方法a()调用类B的方法b( ...

  5. java异常处理机制 (转载)

    java异常处理机制 本文来自:曹胜欢博客专栏.转载请注明出处:http://blog.csdn.net/csh624366188 异常处理是程序设计中一个非常重要的方面,也是程序设计的一大难点,从C ...

  6. Java反射机制(转载)

    原文链接:http://www.blogjava.net/zh-weir/archive/2011/03/26/347063.html Java反射机制是Java语言被视为准动态语言的关键性质.Jav ...

  7. 【转载】Java反射机制详解

    转自:http://baike.xsoftlab.net/view/209.html#3_8 1反射机制是什么 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对 ...

  8. Redisson 分布式锁实战与 watch dog 机制解读

    Redisson 分布式锁实战与 watch dog 机制解读 目录 Redisson 分布式锁实战与 watch dog 机制解读 背景 普通的 Redis 分布式锁的缺陷 Redisson 提供的 ...

  9. Java I/O解读与使用实例

    林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 摘要:本文主要讲解了Java I/O解读与使用实例. 一.I/O基本概念 I/O全称是Inpu ...

随机推荐

  1. windows7 64下redis安装

    1.redis官方下载地址:https://redis.io/download redis 64位下载地址:https://github.com/ServiceStack/redis-windows, ...

  2. day-12函数对象

    函数默认值的细节 如果函数的默认参数的默认值为变量,在所属函数定义阶段一执行就被确定为当时变量存放的值,后面变化不会再变化 a = 100 def fn(num=a): a = 200 fn() 三元 ...

  3. Linux 连接mysql

    连接MYSQL: 格式: mysql -h主机地址 -u用户名 -p用户密码 1.例1:连接到本机上的MYSQL 找到mysql的安装目录,一般可以直接键入命令mysql -uroot -p,回车后提 ...

  4. python 常用库

    Numpy, Pandas 数据处理 Scipy  科学计算 Matplotlib 可视化 Scikit Learn  机器学习 Keras 深度学习模型 jieba 分词 Gensim  主题(包含 ...

  5. java中移位运算

    转自: https://blog.csdn.net/wk1134314305/article/details/74891419

  6. GanttProject 如何显示今天和项目结束

    GanttProject 如何显示今天和项目结束 GanttProject 在甘特图中可以很直观的看出项目开始和结束. 同时也可以看到今天的. 把今天的时间线打开,默认是关闭.

  7. 20175202 《Java程序设计》迭代和JDB

    一.任务详情 二.设计过程的问题及解决 1.程序编译时一直提示编译出现错误. 原因及解决:本以为声明对象和创建对象一起进行时,可以直接采用如zhubajie = new Xiyoujirenwu(); ...

  8. 通过企业微信API接口发送消息

    最近给公司测试组内部开发一个记账小工具,当账目出现问题的时候需要发送消息通知大家,前期主要采用的QQ发送通知消息,但是有一天突然无法连接到QQ服务器,运维的同学建议采用微信的方式对接然后进行告警,所以 ...

  9. Unity 3D中不得不说的yield协程与消息传递

    1. 协程 在Unity 3D中,我们刚开始写脚本的时候肯定会遇到类似下面这样的需求:每隔3秒发射一个烟花.怪物死亡后20秒再复活之类的.刚开始的时候喜欢把这些东西都塞到Update里面去,就像下面这 ...

  10. 视频外同步信号研究---fvh

    视频外同步信号研究---fvh 一个时钟周期有两个edge,分别称为:(1)Leading edge=前一个边沿=第一个边沿,对于开始电压是1,那么就是1变成0的时候:对于开始电压是0,那么就是0变成 ...