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. 时间Date.js

    <span style="line-height: 25.2px;">/** * 日期解析,字符串转日期 * @param dateString 可以为2017-02- ...

  2. javascript 4.2

    element.value="......"也可以为属性设置新的值 setAttribute()方法是“第一级DOM”的组成部分之一,DOM是适用于多种环境和多种程序设计语言的通用 ...

  3. python基础——2、python应用(随机、异常)——(YZ)

    本次的内容为python的应用,关于随机.异常的应用,均多应用列表. 习题一 1.初始化一个数据集,包括5-10位同学的成绩数据(数据类型不限),数据格式如下: 学号 姓名 Java C语言 Pyth ...

  4. 汇编实验1(又是作业emm)

    实验任务:学会使用debug 1.使用Debug,将程序段写入内存: 机器码: b8 20 4e 05 16 14 bb 00 20 01 d8 89 c3 01 d8 b8 1a 00 bb 26 ...

  5. [原] inline operator delete & DLL boundary

    很久以前写在百度空间的这篇文章: [百度空间] [原] 全局operator delete重载到DLL 首先,纠正一个词“重载”,operator new/delete是替换(replacement) ...

  6. 脚本添加crontab任务

    #!/bin/bash export LANG=en_US.utf8 cur_dir=$(cd ``;pwd) job_cmd_info="\n# 每天凌晨5点运行定时删除工具\n" ...

  7. 17.3 删除没用的project

    1.删除某一个或多个无用的project(历史project) 用十六进制编辑器打开"C:\Users\Baymax\Documents\Source Insight 4.0\Project ...

  8. 前端表单提交数据~php获取表单内容

    上图代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...

  9. 代码漏洞扫描描述Cross Site History Manipulation解决办法[dongcoder.com]

    代码漏洞扫描 漏洞描述:Cross Site History Manipulation 简要描述:产品的行为差异或发送不同的反应,在某种程度上暴露了与安全性相关的产品状态,例如特定的操作是否成功.可能 ...

  10. 服务器对接码云webhooks

    服务安装git php代码(外网必须可以访问) <?php //本地路径滚adminasdfdasfasdf $file = "/wwwroot/webhooksLog.txt&quo ...