Java多線程編程之讀寫鎖ReadWriteLock用法實(shí)例
讀寫鎖:分為讀鎖和寫鎖,多個(gè)讀鎖不互斥,讀鎖與寫鎖互斥,這是由jvm自己控制的,你只要上好相應(yīng)的鎖即可。如果你的代碼只讀數(shù)據(jù),可以很多人同時(shí)讀,但不能同時(shí)寫,那就上讀鎖;如果你的代碼修改數(shù)據(jù),只能有一個(gè)人在寫,且不能同時(shí)讀取,那就上寫鎖??傊?,讀的時(shí)候上讀鎖,寫的時(shí)候上寫鎖!
三個(gè)線程讀數(shù)據(jù),三個(gè)線程寫數(shù)據(jù)示例:
可以同時(shí)讀,讀的時(shí)候不能寫,不能同時(shí)寫,寫的時(shí)候不能讀。
讀的時(shí)候上讀鎖,讀完解鎖;寫的時(shí)候上寫鎖,寫完解鎖。
注意finally解鎖。
package com.ljq.test.thread;
import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 讀寫鎖
*
* @author Administrator
*
*/
public class ReadWriteLockTest {
public static void main(String[] args) {
final ReadWrite rw = new ReadWrite();
for (int i = 0; i < 3; i++) {
new Thread() {
public void run() {
while (true) {
rw.read();
}
}
}.start();
new Thread() {
public void run() {
while (true) {
rw.write(new Random().nextInt(10000));
}
}
}.start();
}
}
}
/**
* 讀和寫要互斥,因此要把它們放在同一個(gè)類中
*
* @author Administrator
*
*/
class ReadWrite {
private Object data = null;//共享數(shù)據(jù),只能有一個(gè)線程寫該數(shù)據(jù),但可以有多個(gè)線程同時(shí)讀該數(shù)據(jù)。
ReadWriteLock rwl = new ReentrantReadWriteLock();
/**
* 讀數(shù)據(jù)
*/
public void read() {
rwl.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 {
rwl.readLock().unlock();
}
}
/**
* 寫數(shù)據(jù)
*
* @param data
*/
public void write(Object data) {
rwl.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 {
rwl.writeLock().unlock();
}
}
}
設(shè)計(jì)一個(gè)緩存系統(tǒng)
緩存系統(tǒng):你要取數(shù)據(jù),需調(diào)用我的public Object getData(String key)方法,我要檢查我內(nèi)部有沒(méi)有這個(gè)數(shù)據(jù),如果有就直接返回,如果沒(méi)有,就從數(shù)據(jù)庫(kù)中查找這個(gè)數(shù),查到后將這個(gè)數(shù)據(jù)存入我內(nèi)部的存儲(chǔ)器中,下次再有人來(lái)要這個(gè)數(shù)據(jù),我就直接返回這個(gè)數(shù)不用再到數(shù)據(jù)庫(kù)中找了。你要取數(shù)據(jù)不要找數(shù)據(jù)庫(kù),來(lái)找我。
package com.ljq.test.thread;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 設(shè)計(jì)一個(gè)緩存系統(tǒng)
*
*
* @author Administrator
*
*/
public class CacheDemo {
private Map<String, Object> cache = new HashMap<String, Object>();
public static void main(String[] args) {
String key = "name";
CacheDemo cacheDemo = new CacheDemo();
System.out.println(cacheDemo.getData(key)); //從數(shù)據(jù)庫(kù)獲取數(shù)據(jù)
System.out.println(cacheDemo.getData(key)); //從緩存獲取數(shù)據(jù)
System.out.println(cacheDemo.getData(key)); //從緩存獲取數(shù)據(jù)
}
private ReadWriteLock rwl = new ReentrantReadWriteLock();
public Object getData(String key) {
rwl.readLock().lock(); //上讀鎖
Object value = null;
try {
value = cache.get(key); //先查詢內(nèi)部存儲(chǔ)器中有沒(méi)有要的值
if (value == null) { //如果沒(méi)有,就去數(shù)據(jù)庫(kù)中查詢,并將查到的結(jié)果存入內(nèi)部存儲(chǔ)器中
//釋放讀鎖、上寫鎖
rwl.readLock().unlock();
rwl.writeLock().lock();
try {
if (value == null) { //再次進(jìn)行判斷,防止多個(gè)寫線程堵在這個(gè)地方重復(fù)寫
System.out.println("read data from database");
value = "張三";
cache.put(key, value);
}
} finally {
//設(shè)置完成 釋放寫鎖
rwl.writeLock().unlock();
}
//恢復(fù)讀寫狀態(tài)
rwl.readLock().lock();
}else{
System.out.println("read data from cache");
}
} finally {
rwl.readLock().unlock(); //釋放讀鎖
}
return value;
}
}
返回結(jié)果:

相關(guān)文章
mybatis簡(jiǎn)介與配置_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了mybatis簡(jiǎn)介與配置,介紹了MyBatis+Spring+MySql簡(jiǎn)單配置,有興趣的可以了解一下2017-09-09
java算法題解LeetCode35復(fù)雜鏈表的復(fù)制實(shí)例
這篇文章主要為大家介紹了java算法題解LeetCode35復(fù)雜鏈表的復(fù)制實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
spring的構(gòu)造函數(shù)注入屬性@ConstructorBinding用法
這篇文章主要介紹了關(guān)于spring的構(gòu)造函數(shù)注入屬性@ConstructorBinding用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12
Java跳臺(tái)階實(shí)現(xiàn)思路和代碼
今天小編就為大家分享一篇關(guān)于Java跳臺(tái)階實(shí)現(xiàn)思路和代碼,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-01-01
SpringBoot使用easy-captcha 實(shí)現(xiàn)驗(yàn)證碼登錄功能(解決思路)
文章介紹了如何使用Spring Boot和Easy-Captcha實(shí)現(xiàn)驗(yàn)證碼登錄功能,后端通過(guò)Easy-Captcha生成驗(yàn)證碼并存儲(chǔ)在Redis中,前端獲取驗(yàn)證碼并顯示給用戶,登錄時(shí),前端將用戶輸入的驗(yàn)證碼和標(biāo)識(shí)符發(fā)送到后端進(jìn)行驗(yàn)證,感興趣的朋友跟隨小編一起看看吧2025-02-02
利用MyBatis進(jìn)行不同條件的like模糊查詢的方法
這篇文章主要介紹了利用MyBatis進(jìn)行不同條件的like模糊查詢,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
java實(shí)現(xiàn)電話本管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了JAVA實(shí)現(xiàn)電話本管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-02-02
MyBatis創(chuàng)建存儲(chǔ)過(guò)程的實(shí)例代碼_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
本節(jié)需要用到的有2部分,第一部分是如何在Derby中創(chuàng)建存儲(chǔ)過(guò)程,第二部分是如何在Mybatis中調(diào)用存儲(chǔ)過(guò)程,具體實(shí)例代碼大家參考下本文吧2017-09-09
JAVA基礎(chǔ)類庫(kù)之String類,StringBuffer類和StringBuilder類
這篇文章主要介紹了Java中基礎(chǔ)類庫(kù)的String類,StringBuffer類和StringBuilder類,是Java入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2021-09-09

