`
ldzyz007
  • 浏览: 714999 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

多线程读写资料利器-ReentrantReadWriteLock

    博客分类:
  • java
阅读更多
多线程读写文件利器-ReentrantReadWriteLock
理解线程,首先要明白线程的几种状态,以及状态之间的转换,具体参考下图:




其次,必须理解线程中"锁"的作用,以下引用自sun公司文档Threads and Locks一章中关于Locks的描述:

引用
The Java programming language provides multiple mechanisms for communicating between threads. The most basic of these methods is synchronization, which is implemented using monitors. Each object in Java is associated with a monitor, which a thread can lock or unlock. Only one thread at a time may hold a lock on a monitor. Any other threads attempting to lock that monitor are blocked until they can obtain a lock on that monitor. A thread t may lock a particular monitor multiple times; each unlock reverses the effect of one lock operation.


以上说明,对于多线程来说,正是依靠锁定Object的Monitor来保证同一时间只有一个线程持有某个特定的锁.

Java API中定义Object的wait(),notify()方法就是基于其Monitor来实现:

引用
notify(): Wakes up a single thread that is waiting on this object's monitor.
wait(): Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.
notifyAll(),wait(long timeout),wait(long timeout, int nanos)...


对于Object Monitor来说,可参考Analyzing Stack Traces文档关于Monitor的部分说明及种类介绍:

引用
A monitor can be thought of as a lock on an object, and every object has a monitor.
...
The following table describes the common registered monitors:


Monitor Description
utf8 hash table Locks the hashtable of defined i18N Strings that were loaded from the class constant pool.
JNI pinning lock Protects block copies of arrays to native method code.
JNI global reference lock Locks the global reference table which holds values that need to be explicitly freed, and will outlive the lifetime of the native method call.
BinClass lock Locks access to the loaded and resolved classes list. The global table list of classes
Class linking lock Protects a classes data when loading native libraries to resolve symbolic references
System class loader lock Ensures that only one thread is loading a system class at a time.
Code rewrite lock Protects code when an optimization is attempted.
Heap lock Protects the Java heap during heap memory management
Monitor cache lock Only one thread can have access to the monitor cache at a time this lock ensures the integrity of the monitor cache
Dynamic loading lock Protects Unix green threads JVMs from loading the shared library stub libdl.so more than once at a time.
Monitor IO lock Protects physical I/O for example, open and read.
User signal monitor Controls access to the signal handler if a user signal USRSIG in green threads JVMs.
Child death monitor Controls access to the process wait information when using the runtime system calls to run locals commands in a green threads JVM.
I/O Monitor Controls access to the threads file descriptors for poll/select events
Alarm Monitor Controls access to a clock handler used in green threads JVMs to handle timeouts
Thread queue lock Protects the queue of active threads
Monitor registry Only one thread can have access to the monitor registry at a time this lock ensures the integrity of that registry
Has finalization queue lock * Protects the list of queue lock objects that have been garbage-collected, and deemed to need finalization. They are copied to the Finalize me queue
Finalize me queue lock * Protects a list of objects that can be finalized at leisure
Name and type hash table lock * Protects the JVM hash tables of constants and their types
String intern lock * Locks the hashtable of defined Strings that were loaded from the class constant pool
Class loading lock * Ensures only one thread loads a class at a time
Java stack lock * Protects the free stack segments list



多线程下的数据操作需要保证其数据的可靠一致性,为此必须实现线程的同步.以下引用自Intrinsic Locks and Synchronization:

引用
Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The API specification often refers to this entity simply as a "monitor.") Intrinsic locks play a role in both aspects of synchronization: enforcing exclusive access to an object's state and establishing happens-before relationships that are essential to visibility.

Every object has an intrinsic lock associated with it. By convention, a thread that needs exclusive and consistent access to an object's fields has to acquire the object's intrinsic lock before accessing them, and then release the intrinsic lock when it's done with them. A thread is said to own the intrinsic lock between the time it has acquired the lock and released the lock. As long as a thread owns an intrinsic lock, no other thread can acquire the same lock. The other thread will block when it attempts to acquire the lock.

When a thread releases an intrinsic lock, a happens-before relationship is established between that action and any subsequent acquistion of the same lock.

Locks In Synchronized Methods
...
Synchronized Statements
...
Reentrant Synchronization
...


对于以上部分,需要注意以下几点:

1. 线程同步的部分为整个Synchronized同步方法,整个Synchronized同步块,或是Reentrant同步中上锁(lock())与开锁(unlock())之间的部分.

2. 对于多线程synchronized同步块的锁定, 应该限制为锁定同一个Object对象:

synchronized(Object obj){}  注: 如果每个线程锁定的对象不同,则线程之间互不影响,无法达到同步效果.

synchronized同步块还可以直接锁定某个类的所有对象:

synchronized(XXX.class){}  注意没有static synchronized(XXX){}的用法.

锁定对象的线程与锁定类的线程之间互不影响.

3. 对于synchronized同步方法:

①public synchronized void method(){...}  锁定当前对象
②public static synchronized void method(){...}  锁定当前类的所有对象

3.① 等价于public void method(){ synchronized(this){} }
3.② 等价于public void method(){ synchronized(this.class){} }

4. Reentrant同步锁:

线程锁定靠的是Reentrant锁, 依靠调用其lock(),unlock()方法来决定何时何地执行同步.

(1) 与synchronized相比, 使用ReentrantLock(public class ReentrantLock extends Object implements Lock, Serializable),可更加精准的控制线程.

①可以判断线程持有(isHeldByCurrentThread(),isLocked())
②可以用于中断线程(lockInterruptibly())
③设置线程排队的公平性(构造方法)

(2) 专门读写文件, 可使用ReentrantReadWriteLock(public class ReentrantReadWriteLock extends Object implements ReadWriteLock, Serializable)

①该锁专门为多用户读取文件设计,因此封装了读和写之间的关系:允许多用户读(读-读)以及写文件时读(写-读),禁止读文件时写(读-写)以及写文件时再次写(写-写).
②包含两个属性readLock和writeLock, 这两个属性封装好了上述功能, 调用时直接lock(),unlock()即可.
③readLock和writeLock是通过升级(readLock -> writeLock)以及降级(writeLock -> readLock)来完成上述功能, 以下为Java API中的例子:

class CachedData {
Object data;
volatile boolean cacheValid;
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

void processCachedData() {
rwl.readLock().lock();
if (!cacheValid) {
// Must release read lock before acquiring write lock
rwl.readLock().unlock();
rwl.writeLock().lock();
// Recheck state because another thread might have acquired
// write lock and changed state before we did.
if (!cacheValid) {
data = ...
cacheValid = true;
}
// Downgrade by acquiring read lock before releasing write lock
rwl.readLock().lock();
rwl.writeLock().unlock(); // Unlock write, still hold read
}

use(data);
rwl.readLock().unlock();
}
}




以下代码为自己练习操作ReentrantReadWriteLock的代码:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
* 对原始数据进行操作的类
*
* @author Vincent.zheng
*/
class Oper {

private Map<String, String> sourceMap = new HashMap<String, String>();
private ReadWriteLock lock = new ReentrantReadWriteLock(true);
private final Lock readLock = lock.readLock();
private final Lock writeLock = lock.writeLock();

protected Oper() {
setSourceMap();
}

// 读取单个值
public String read(String key) {

try {
readLock.lock();
launchPeriod();
return key + ":" + sourceMap.get(key);
} finally {
readLock.unlock();
}
}

//
public String read() {
try {
readLock.lock();
launchPeriod();

StringBuffer results = new StringBuffer();
String[] str = new String[sourceMap.size()];
String[] keys = sourceMap.keySet().toArray(str);
for (String key : keys) {
results.append(key + ":" + sourceMap.get(key) + "; ");
}
return new String(results);
} finally {
readLock.unlock();
}
}

public String write(String key, String value) {

try {
writeLock.lock();
launchPeriod();
sourceMap.put(key, value);
return key + ":" + value;
} finally {
writeLock.unlock();
}
}

public String write(Map<String, String> map) {
try {
writeLock.lock();
launchPeriod();
sourceMap.putAll(map);

StringBuffer results = new StringBuffer();
String[] str = new String[map.size()];
String[] keys = map.keySet().toArray(str);
for (String key : keys) {
results.append(key + ":" + map.get(key) + "; ");
}
return new String(results);
} finally {
writeLock.unlock();
}
}

// 保证每个线程运行时间在5秒以上
private void launchPeriod() {
long currentTime = System.currentTimeMillis();
for (;;) {
if (System.currentTimeMillis() - currentTime > 5000) {
break;
}
}
}

// 原始数据
private void setSourceMap() {
for (int i = 0; i < 1000; i++) {
sourceMap.put("SourceKey" + i, "SourceValue" + i);
}
}
}

class Reader extends Thread {

public Oper oper;

public Reader(String name, Oper oper) {
super(name);
this.oper = oper;
}

public void run() {

String name = Thread.currentThread().getName();
System.out.println(name + " Start Reading");
// 读全部数据
// String results = oper.read();
// System.out.println(name + " Read=======" + results);
// 读单个随机值
String result = oper.read("SourceKey" + new Random().nextInt(1000));
System.out.println(name + " Read=======" + result);
}
}

class Writer extends Thread {

public Oper oper;

public Writer(String str, Oper oper) {
super(str);
this.oper = oper;
}

public void run() {

String name = Thread.currentThread().getName();
System.out.println(name + " Start Writing");

// 写全部数据
// String results = oper.write(getWriteData());
// System.out.println(name + " Write=======" + results);

// 写单个值
String result = oper.write("WriteSoloKeyIn" + name, "WriteSoloValueIn"
+ name);
System.out.println(name + " Write=======" + result);
System.out.println(name + " Read=======" + oper.read());
}

// 写入数据
private Map<String, String> getWriteData() {
Map<String, String> writeMap = new HashMap<String, String>();
for (int i = 0; i < 10; i++) {
writeMap.put("WriteKey" + (i + 1), "WriteValue" + (i + 1));
}
return writeMap;
}

}

public class Test {

/**
* @param args
*/
public static void main(String[] args) {

final Oper oper = new Oper();
ArrayList<Thread> list = new ArrayList<Thread>();

for (int i = 0; i < 100; i++) {
Reader reader = new Reader("Reader" + i, oper);
list.add(reader);
}

for (int i = 0; i < 10; i++) {
Writer writer = new Writer("Writer" + i, oper);
list.add(writer);
}

ArrayList<Integer> data = new ArrayList<Integer>();
for (int i = 0; i < list.size(); i++) {
data.add(i);
}
for (int i = 0; i < list.size(); i++) {
Integer random = new Random(i).nextInt(list.size());
if (data.contains(random)) {
data.remove(random);
list.get(random).start();
}
}
}
}
  • 大小: 12 KB
分享到:
评论

相关推荐

    Java 多线程与并发(12-26)-JUC锁- ReentrantReadWriteLock详解.pdf

    在Java多线程并发编程中,ReentrantReadWriteLock(可重入读写锁)是一个重要的同步工具,它属于Java并发包(java.util.concurrent.locks)中的一个类。这个锁提供了比标准的synchronized关键字更细粒度的控制,允许...

    60.Lock-ReentranLock-ReentrantReadWriteLock.mp4

    在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。

    08、读写锁ReentrantReadWriteLock&StampLock详解-ev

    读写锁ReentrantReadWriteLock&StampLock详解_e读写锁ReentrantReadWriteLock&StampLock详解_e读写锁ReentrantReadWriteLock&StampLock详解_e读写锁ReentrantReadWriteLock&StampLock详解_e读写锁...

    java 多线程编程实战指南(核心 + 设计模式 完整版)

    - **读写锁**:`ReentrantReadWriteLock`提供读写分离的锁机制,提高并发效率。 6. **并发编程最佳实践** - **避免过度使用同步**:合理利用非阻塞并发工具,减少线程上下文切换。 - **线程局部变量**:`...

    java多线程、锁的教程跟案例

    - ReadWriteLock(读写锁):ReentrantReadWriteLock提供了读写分离的锁,允许多个读线程同时访问,但写线程独占资源。 2. **乐观锁** - CAS(Compare and Swap):无锁算法,基于硬件原子操作,检查并更新值,...

    多线程文件读写ThreadREADWrite

    本文将详细探讨如何使用多线程来实现对同一个文件的读写操作,以及在这一过程中可能遇到的问题和解决方案。 标题中的"多线程文件读写ThreadREADWrite"指的是在同一时间内,通过两个或更多的线程分别进行文件的读取...

    8、读写锁ReentrantReadWriteLock&StampLock详解.pdf

    读写锁是一种特殊的锁机制,它可以支持多个线程同时读取共享资源,但在任何时刻只允许一个线程修改这个资源。这种类型的锁非常适合那些读操作远远多于写操作的场景。具体来说: - **读读共享**:多个线程可以同时...

    笔记16-JAVAEE之多线程进阶

    Java 多线程进阶 - 锁策略与读写锁 在 Java 多线程编程中,锁策略和读写锁是两个非常重要的概念。本文将对 Java 多线程进阶中的锁策略和读写锁进行详细介绍。 锁策略 在多线程编程中,锁策略是一个非常重要的概念...

    人工智能-项目实践-多线程-多线程与高并发.zip

    此外,同步机制是多线程编程中的关键,包括互斥锁(synchronized关键字)、读写锁(ReentrantReadWriteLock)、条件变量(Condition)等,它们确保了共享数据在多线程环境下的安全性。避免死锁和活锁也是多线程编程...

    java多线程设计模式_java_设计模式_多线程_多线程课题_

    Java多线程设计模式是Java开发中的核心概念,它涉及到如何高效、安全地在多个执行线程之间共享资源和协调任务。设计模式是解决特定问题的成熟方案,它们是编程经验的结晶,可以帮助开发者在面临多线程挑战时快速找到...

    Java+并发性和多线程

    Java并发性和多线程是Java开发中至关重要的概念,它们涉及到如何在单个或多个处理器上同时执行程序的不同部分,从而提升程序的效率和响应速度。在这个领域,Java提供了丰富的工具和API,使得开发者能够有效地管理和...

    java多线程经典案例

    Java多线程是Java编程中的重要概念,它允许程序同时执行多个任务,极大地提升了程序的效率和性能。在Java中,实现多线程有两种主要方式:通过实现Runnable接口或者继承Thread类。本案例将深入探讨Java多线程中的关键...

    Java互联网架构多线程并发编程原理及实战 视频教程 下载.zip

    Java互联网架构多线程并发编程原理及实战 视频教程 下载 1-1 课程简介.mp4 1-2 什么是并发编程.mp4 1-3 并发编程的挑战之频繁的上下文切换.mp4 1-4 并发编程的挑战之死锁.mp4 1-5 并发编程的挑战之线程安全....

    Java互联网架构多线程并发编程原理及实战 视频教程 下载4.zip

    Java互联网架构多线程并发编程原理及实战 视频教程 下载 1-1 课程简介.mp4 1-2 什么是并发编程.mp4 1-3 并发编程的挑战之频繁的上下文切换.mp4 1-4 并发编程的挑战之死锁.mp4 1-5 并发编程的挑战之线程安全....

    Java互联网架构多线程并发编程原理及实战 视频教程 下载2.zip

    Java互联网架构多线程并发编程原理及实战 视频教程 下载 1-1 课程简介.mp4 1-2 什么是并发编程.mp4 1-3 并发编程的挑战之频繁的上下文切换.mp4 1-4 并发编程的挑战之死锁.mp4 1-5 并发编程的挑战之线程安全....

    Java互联网架构多线程并发编程原理及实战 视频教程 下载3.zip

    Java互联网架构多线程并发编程原理及实战 视频教程 下载 1-1 课程简介.mp4 1-2 什么是并发编程.mp4 1-3 并发编程的挑战之频繁的上下文切换.mp4 1-4 并发编程的挑战之死锁.mp4 1-5 并发编程的挑战之线程安全....

    Java互联网架构多线程并发编程原理及实战 视频教程 下载1.zip

    Java互联网架构多线程并发编程原理及实战 视频教程 下载 1-1 课程简介.mp4 1-2 什么是并发编程.mp4 1-3 并发编程的挑战之频繁的上下文切换.mp4 1-4 并发编程的挑战之死锁.mp4 1-5 并发编程的挑战之线程安全....

    27道顶尖的Java多线程、锁、内存模型面试题!.zip

    Java多线程、锁以及内存模型是Java编程中极为关键且深入的部分,它们涉及到程序的并发性能、稳定性以及数据一致性。下面将详细讲解这些领域的核心知识点。 1. **Java多线程** - **线程定义**:线程是程序执行的...

    MCA 多线程&高并发.zip

    《MCA多线程&高并发》学习指南 在Java编程中,多线程和高并发是提升系统性能的关键技术。对于初中级开发者而言,掌握这些技能至关重要,因为它们能够帮助我们构建出更加高效、响应迅速的应用。本教程将深入探讨多...

    Java多线程 ReentrantReadWriteLock原理及实例详解

    读写锁允许多个线程同时读取共享资源,但写操作是互斥的,确保数据的一致性。 ### 1. 读写锁的基本概念 - **共享锁(读锁)**:读锁是共享的,意味着多个线程可以同时获取读锁,进行读操作。读操作之间不会产生...

Global site tag (gtag.js) - Google Analytics