Java锁_读写锁
独占锁:是指锁一次只能被一个线程持有,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锁_读写锁的更多相关文章
- 二、多线程基础-乐观锁_悲观锁_重入锁_读写锁_CAS无锁机制_自旋锁
1.10乐观锁_悲观锁_重入锁_读写锁_CAS无锁机制_自旋锁1)乐观锁:就像它的名字一样,对于并发间操作产生的线程安全问题持乐观状态,乐观锁认为竞争不总是会发生,因此它不需要持有锁,将 比较-设置 ...
- 多线程编程之Apue3rd_Chapter11之互斥锁_读写锁_自旋锁
学习了apue3rd的第11章,主要讲的是多线程编程.因为线程共享进程的资源比如堆和全局变量,多线程编程最重要的是,使用各种锁进行线程同步. 线程编程首先要学习的三个函数如下: #include &l ...
- JAVA锁机制-可重入锁,可中断锁,公平锁,读写锁,自旋锁,
如果需要查看具体的synchronized和lock的实现原理,请参考:解决多线程安全问题-无非两个方法synchronized和lock 具体原理(百度) 在并发编程中,经常遇到多个线程访问同一个 ...
- Java中的锁-悲观锁、乐观锁,公平锁、非公平锁,互斥锁、读写锁
总览图 如果文中内容有错误,欢迎指出,谢谢. 悲观锁.乐观锁 悲观锁.乐观锁使用场景是针对数据库操作来说的,是一种锁机制. 悲观锁(Pessimistic Lock):顾名思义,就是很悲观,每次去拿数 ...
- golang互斥锁和读写锁
一.互斥锁 互斥锁是传统的并发程序对共享资源进行访问控制的主要手段.它由标准库代码包sync中的Mutex结构体类型代表.sync.Mutex类型(确切地说,是*sync.Mutex类型)只有两个公开 ...
- 从自旋锁、睡眠锁、读写锁到 Linux RCU 机制讲解
同步自我的 csdn 博客 6.S081 从自旋锁.睡眠锁.读写锁到 Linux RCU 机制讲解_我说我谁呢 --CSDN博客 总结一下 O/S 课程里面和锁相关的内容. 本文是 6.S0 ...
- Go语言基础之13--线程安全及互斥锁和读写锁
一.线程安全介绍 1.1 现实例子 A. 多个goroutine同时操作一个资源,这个资源又叫临界区 B. 现实生活中的十字路口,通过红路灯实现线程安全 C. 火车上的厕所(进去之后先加锁,在上厕所, ...
- 多线程编程_读写锁ReadWriteLock
Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象.两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象. 读写锁:分为读 ...
- PHP程序中的文件锁、互斥锁、读写锁使用技巧解析
文件锁全名叫 advisory file lock, 书中有提及. 这类锁比较常见,例如 mysql, php-fpm 启动之后都会有一个pid文件记录了进程id,这个文件就是文件锁. 这个锁可以防止 ...
随机推荐
- JavaScript图形实例:迭代函数系统生成图形
迭代函数系统(Iterated Function System,IFS)可以用来创建分形图案,它是分形理论的重要分支,也是分形图形处理中最富生命力而且最具有广阔应用前景的领域之一.这一工作最早可以追溯 ...
- GAN网络从入门教程(二)之GAN原理
在一篇博客GAN网络从入门教程(一)之GAN网络介绍中,简单的对GAN网络进行了一些介绍,介绍了其是什么,然后大概的流程是什么. 在这篇博客中,主要是介绍其数学公式,以及其算法流程.当然数学公式只是简 ...
- 列拖拽顺序调整-sortable.js使用
最近在做一个单表统计功能,涉及到一个查询列配置,但是查询出来的列顺序,可以进行配置,通过写列的排序当然阔以,但是方法就不美丽了.所以,在网上搜了一下拖拽的组件,最终定位Sortable.js,简单易用 ...
- uni-app中textarea组件
textarea组件,官方给出的监听事件有以下事件: 其中一定要注意,当使用 v-model 对表单内容进行双向绑定的时候,@input 事件是在绑定变量变化前触发的,所以如果在input事件内打印绑 ...
- 二、kafka 中央控制器、主题、分区、副本
集群和中央控制器 一个独立的Kafka服务器被称为broker.broker用来接收来自生产者的消息,为消息设置偏移量,并把消息保存到磁盘.换句话说,多个kafka实例组成kafka集群,每个实例(s ...
- 你是如何理解Vue的响应式系统的
1.响应式系统简述: 任何一个 Vue Component 都有一个与之对应的 Watcher 实例. Vue 的 data 上的属性会被添加 getter 和 setter 属性. 当 Vue Co ...
- 【Nginx】如何获取客户端真实IP、域名、协议、端口?看这一篇就够了!
写在前面 Nginx最为最受欢迎的反向代理和负载均衡服务器,被广泛的应用于互联网项目中.这不仅仅是因为Nginx本身比较轻量,更多的是得益于Nginx的高性能特性,以及支持插件化开发,为此,很多开发者 ...
- flask源码剖析系列(系列目录)
flask源码剖析系列(系列目录) 01 flask源码剖析之werkzurg 了解wsgi 02 flask源码剖析之flask快速使用 03 flask源码剖析之threading.local和高 ...
- iis 0x80070032 Cannot read configuration file because it exceeds the maximum file size
问题:iis部署了网站,由于webconfig文件过大(251kb,默认250kb)导致网站报错 0x80070032 Cannot read configuration file because i ...
- 动手实现 LRU 算法,以及 Caffeine 和 Redis 中的缓存淘汰策略
我是风筝,公众号「古时的风筝」. 文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在里面. 那天我在 LeetCode 上刷到一道 LRU 缓存机制的问题, ...