独占锁:是指锁一次只能被一个线程持有,ReentrantLock和Synchronized都是独占锁。

共享锁:是指锁可以被多个线程持有。

对于ReentrantReadWriteLock,其读锁是共享锁,写锁是独占锁。

代码示例:如果不设置锁,下面这块代码执行后就会造成一段写操作在完成之前被多个其他操作打断。

 package com.freud.algorithm.other;

 import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* 资源类
*/
class MyCache { private volatile Map<String, Object> map = new HashMap<>();
// private Lock lock = new ReentrantLock();
public void put(String key, Object value) { System.out.println(Thread.currentThread().getName() + "\t 正在写入:" + key);
// 暂停一会儿线程
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "\t 写入完成");
} public void get(String key) { System.out.println(Thread.currentThread().getName() + "\t 正在读取:");
// 暂停一会儿线程
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
Object value = map.get(key);
System.out.println(Thread.currentThread().getName() + "\t 读取完成:" + value);
}
} /**
* 多个线程同时读一个资源类没有任何问题,所以为了满足并发量,读取共享资源应该可以同时进行
* 但是,如果有一个线程想去写共享资源,就不应该再有其他线程可以对这个资源进行读或者写
* 小总结:
* 读-读能共存
* 读-写不能共存
* 写-写不能共存
*/
public class ReadWriteLockDemo { public static void main(String[] args) { MyCache myCache = new MyCache(); for (int i = 0; i < 5; i++) {
final int tempInt = i;
new Thread(() -> {
myCache.put(tempInt + "", tempInt + "");
}, String.valueOf(i)).start();
} for (int i = 0; i < 5; i++) {
final int tempInt = i;
new Thread(() -> {
myCache.get(tempInt + "");
}, String.valueOf(i)).start();
}
}
}

打印:

 "C:\Program Files\Java\jdk1.8.0_191\bin\java" "-javaagent:E:\Jetbrains\IntellijIDEA\IntelliJ IDEA 2017.2.6\lib\idea_rt.jar=12592:E:\Jetbrains\IntellijIDEA\IntelliJ IDEA 2017.2.6\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_191\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\rt.jar;E:\practise\algorithm\out\production\algorithm" com.freud.algorithm.other.ReadWriteLockDemo
1 正在写入:1
0 正在写入:0
2 正在写入:2
3 正在写入:3
4 正在写入:4
0 正在读取:
1 正在读取:
2 正在读取:
3 正在读取:
4 正在读取:
1 写入完成
1 读取完成:1
0 读取完成:0
0 写入完成
2 写入完成
4 写入完成
3 写入完成
4 读取完成:null
3 读取完成:null
2 读取完成:2 Process finished with exit code 0

为了解决这个问题,使得写操作保证原子性不被其他线程打断,加了ReadWriteLock。

 package com.freud.algorithm.other;

 import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; /**
* 资源类
*/
class MyCache { private volatile Map<String, Object> map = new HashMap<>();
// 传统的Lock不足以满足需求
// private Lock lock = new ReentrantLock();
/**
* JUC提供了ReentrantReadWriteLock
*/
private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); /**
* put方法
* @param key
* @param value
*/
public void put(String key, Object value) { rwLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "\t 正在写入:" + key);
// 暂停一会儿线程
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "\t 写入完成");
} catch (Exception e) {
e.printStackTrace();
} finally {
rwLock.writeLock().unlock();
}
} /**
* get方法
* @param key
*/
public void get(String key) { rwLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "\t 正在读取:");
// 暂停一会儿线程
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
Object value = map.get(key);
System.out.println(Thread.currentThread().getName() + "\t 读取完成:" + value);
} catch (Exception e) {
e.printStackTrace();
} finally {
rwLock.readLock().unlock();
}
}
} /**
* 多个线程同时读一个资源类没有任何问题,所以为了满足并发量,读取共享资源应该可以同时进行
* 但是,如果有一个线程想去写共享资源,就不应该再有其他线程可以对这个资源进行读或者写
* 小总结:
* 读-读能共存
* 读-写不能共存
* 写-写不能共存
*/
public class ReadWriteLockDemo { public static void main(String[] args) { MyCache myCache = new MyCache(); for (int i = 0; i < 5; i++) {
final int tempInt = i;
new Thread(() -> {
myCache.put(tempInt + "", tempInt + "");
}, String.valueOf(i)).start();
} for (int i = 0; i < 5; i++) {
final int tempInt = i;
new Thread(() -> {
myCache.get(tempInt + "");
}, String.valueOf(i)).start();
}
}
}

打印:

"C:\Program Files\Java\jdk1.8.0_191\bin\java" "-javaagent:E:\Jetbrains\IntellijIDEA\IntelliJ IDEA 2017.2.6\lib\idea_rt.jar=18187:E:\Jetbrains\IntellijIDEA\IntelliJ IDEA 2017.2.6\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_191\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\rt.jar;E:\practise\algorithm\out\production\algorithm" com.freud.algorithm.other.ReadWriteLockDemo
0 正在写入:0
0 写入完成
1 正在写入:1
1 写入完成
2 正在写入:2
2 写入完成
3 正在写入:3
3 写入完成
4 正在写入:4
4 写入完成
1 正在读取:
0 正在读取:
3 正在读取:
4 正在读取:
2 正在读取:
2 读取完成:2
4 读取完成:4
3 读取完成:3
0 读取完成:0
1 读取完成:1 Process finished with exit code 0

Java锁_读写锁的更多相关文章

  1. 二、多线程基础-乐观锁_悲观锁_重入锁_读写锁_CAS无锁机制_自旋锁

    1.10乐观锁_悲观锁_重入锁_读写锁_CAS无锁机制_自旋锁1)乐观锁:就像它的名字一样,对于并发间操作产生的线程安全问题持乐观状态,乐观锁认为竞争不总是会发生,因此它不需要持有锁,将 比较-设置 ...

  2. 多线程编程之Apue3rd_Chapter11之互斥锁_读写锁_自旋锁

    学习了apue3rd的第11章,主要讲的是多线程编程.因为线程共享进程的资源比如堆和全局变量,多线程编程最重要的是,使用各种锁进行线程同步. 线程编程首先要学习的三个函数如下: #include &l ...

  3. JAVA锁机制-可重入锁,可中断锁,公平锁,读写锁,自旋锁,

    如果需要查看具体的synchronized和lock的实现原理,请参考:解决多线程安全问题-无非两个方法synchronized和lock 具体原理(百度) 在并发编程中,经常遇到多个线程访问同一个 ...

  4. Java中的锁-悲观锁、乐观锁,公平锁、非公平锁,互斥锁、读写锁

    总览图 如果文中内容有错误,欢迎指出,谢谢. 悲观锁.乐观锁 悲观锁.乐观锁使用场景是针对数据库操作来说的,是一种锁机制. 悲观锁(Pessimistic Lock):顾名思义,就是很悲观,每次去拿数 ...

  5. golang互斥锁和读写锁

    一.互斥锁 互斥锁是传统的并发程序对共享资源进行访问控制的主要手段.它由标准库代码包sync中的Mutex结构体类型代表.sync.Mutex类型(确切地说,是*sync.Mutex类型)只有两个公开 ...

  6. 从自旋锁、睡眠锁、读写锁到 Linux RCU 机制讲解

    ​    同步自我的 csdn 博客 6.S081 从自旋锁.睡眠锁.读写锁到 Linux RCU 机制讲解_我说我谁呢 --CSDN博客 总结一下 O/S 课程里面和锁相关的内容. 本文是 6.S0 ...

  7. Go语言基础之13--线程安全及互斥锁和读写锁

    一.线程安全介绍 1.1 现实例子 A. 多个goroutine同时操作一个资源,这个资源又叫临界区 B. 现实生活中的十字路口,通过红路灯实现线程安全 C. 火车上的厕所(进去之后先加锁,在上厕所, ...

  8. 多线程编程_读写锁ReadWriteLock

    Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象.两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象. 读写锁:分为读 ...

  9. PHP程序中的文件锁、互斥锁、读写锁使用技巧解析

    文件锁全名叫 advisory file lock, 书中有提及. 这类锁比较常见,例如 mysql, php-fpm 启动之后都会有一个pid文件记录了进程id,这个文件就是文件锁. 这个锁可以防止 ...

随机推荐

  1. Centos 6.4 安装KSnapshot 和gimp截图工具

    一. # wget http://www.ibiblio.org/pub/Linux/X11/xutils/ksnapshot-0.2.7.tar.gz # tar -zxvf ksnapshot-0 ...

  2. 【2003、2004 NOIp 入门组错题报告】

    2003: T4: 题目大意:  讲这么多话,其实就是求比当前序列大的序列中第m小的一个.可以每次找出比当前序列大的最小的一个序列.我们可以从后往前扫描,当当前这个数比后一个数小时,我们把它与它后面的 ...

  3. java语言进阶(三)_List_Set_数据结构_Collections

    主要内容 数据结构 List集合 Set集合 Collections 第一章 数据结构 1.1 数据结构有什么用? 常见的数据结构:堆.栈.队列.数组.链表和红黑树 . 1.2 常见的数据结构 栈 栈 ...

  4. c# 操作Redis的五种基本类型总结

    在我们的项目中,通常会把数据存储到关系型数据库中,比如Oracle,SQL Server,Mysql等,但是关系型数据库对于并发的支持并不是很强大,这样就会造成系统的性能不佳,而且存储的数据多为结构化 ...

  5. 解决移动端点击穿透问题_h5实现移动端点击事件穿透的多种解决方案

    移动端点透点透现象出现的场景: 当A/B两个层上下z轴重叠,上层的A点击后消失或移开(这一点很重要),并且B元素本身有默认click事件(如a标签)或绑定了click事件.在这种情况下,点击A/B重叠 ...

  6. Golang从合并链表聊递归

    从合并链表聊递归 递归是工程师最常见的一种解决问题的方式,但是有时候不容易真正掌握.有人说是看起来很简单,自己写起来会费点劲. 最著名的例子就是斐波那契数列(Fibonacci sequence),通 ...

  7. 【线型DP】CF1012C Hills 小山坡

    来了来了. 题目: 给你n个数,你一次操作可以把某一个数-1(可以减为负数),你的目标是使任意的k个数严格小于它旁边的两个数(第一个数只用严格小于第二个数,第n个数只用严格小于第n-1个数),问最少需 ...

  8. 记一次使用elasticsearch遇到bug的探索过程

    背景: 练习一个小项目,爬取京东的数据,存到ES库中,然后读取ES库中数据,展示到页面上.效果图如下: 涉及两个接口,一个爬取写入ES接口,一个查询展示接口,当我写完代码信心满满准备看看效果的时候,调 ...

  9. scrapy 基础组件专题(十四):scrapy CookiesMiddleware源码

    一 Scrapy框架--cookie的获取/传递/本地保存 1. 完成模拟登陆2. 登陆成功后提取出cookie,然后保存到本地cookie.txt文件中3. 再次使用时从本地的cookie.txt中 ...

  10. Tomcat的基本使用及相关知识的概述(超详细版)

    絮絮叨叨: 在深入了解Tomcat源码之前,本来是想亲自写一篇Tomcat的基本使用教程的,在网上兜兜转转发现了这篇博客:https://blog.csdn.net/weixin_40396459/a ...