java5线程框架Executor 读写锁的例子
为了提高效率有些共享资源允许同时进行多个读的操作,但只允许一个写的操作,比如一个文件,只要其内容不变可以让多个线程同时读,不必做排他的锁定,排他 的锁定只有在写的时候需要,以保证别的线程不会看到数据不完整的文件。 ReadWriteLock 可满足这种需要。 ReadWriteLock 内置两个 Lock ,一个是读的 Lock ,一个是写的 Lock 。多个线程可同时得到读的 Lock ,但只有一个线程能得到写的 Lock ,而且写的 Lock 被锁定后,任何线程都不能得到 Lock 。
这里模拟了这样一个场景:
在ReadWriteLockOperator对象里设置一个共享资源 shareResources 。
有3个读者(A, B, C)一直连续的从 shareResources 获取信息, 然后输出到
控制台 ;有一个作者每隔60秒往 shareResources 加入信息, 加信息的过程
相对耗时, 在这段时间, 任何读者都不能访问 shareResources。
写了4个类来验证这种情况,只在windows下做了测试。
1.1、
ReadTask.java
读任务
1.2、
WriteTask.java
写任务
1.3、
ReadWriteLockLogic.java
读写操作的逻辑
1.4、
ReadWriteLockTest.java
带有main方法的测试类
================= 1.1 ReadTask.java
=====================
package Executor;
//可执行任务
public class ReadTask extends Thread {
//logic bean
private ReadWriteLockLogic
readWriteLockOperator;
//读者
private String reader;
public ReadTask(ReadWriteLockLogic
readWriteLockOperator, String reader) {
this.readWriteLockOperator = readWriteLockOperator;
this.reader
= reader;
}
private ReadTask(){}
// 执行任务
public void run() {
if(this.readWriteLockOperator != null){
try {
while(!isInterrupted()){
Thread.sleep(200);
System.out.println(reader + " read:" +
Thread.currentThread().toString() + " : " +
this.readWriteLockOperator.read());
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
}
========================= 1.1 end
========================
================= 1.2 WriteTask.java
=====================
package Executor;
//可执行任务
public class WriteTask extends Thread{
//logic bean
private ReadWriteLockLogic
readWriteLockOperator;
//作者
private String writer;
public WriteTask(ReadWriteLockLogic
readWriteLockOperator, String writer) {
this.readWriteLockOperator = readWriteLockOperator;
this.writer
= writer;
}
private WriteTask(){}
// 一个很耗时的写任务
public void run() {
try {
while(!isInterrupted()){
Thread.sleep(100);
this.readWriteLockOperator.write(this.writer, "hehehhe");
}
} catch
(Exception e) {
// TODO: handle exception
}
}
}
========================= 1.2 end
==========================
================= 1.3 ReadWriteLockLogic.java
==============
package Executor;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
//读写操作的逻辑
public class ReadWriteLockLogic {
// 初始化一个 ReadWriteLock
private ReadWriteLock lock = new
ReentrantReadWriteLock();
//共享资源
private
List<String> shareResources = new
ArrayList<String>(0);
//读
public String read() {
// 得到
readLock 并锁定
Lock
readLock = lock.readLock();
readLock.lock();
try
{
// 读相对省时,做空循环 大约0.5second
for(int i=0 ;i<2500000; i++){
System.out.print("");
}
// 做读的工作
StringBuffer buffer = new StringBuffer();
for (String shareResource : shareResources) {
buffer.append(shareResource);
buffer.append("/t");
}
return buffer.toString();
} finally
{
readLock.unlock();//一定要保证锁的释放
}
}
//写
public void write(String writer, String content)
{
// 得到
writeLock 并锁定
Lock
writeLock = lock.writeLock();
writeLock.lock();
try
{
System.out.println(writer + " write ===" +
Thread.currentThread().toString());
// 写比较费时,所以做空循环 大约13second
for(int i=0 ;i<50000000; i++){
System.out.print("");
System.out.print("");
}
// 做写的工作
int count = shareResources.size();
for (int i=count; i < count + 1; i++) {
shareResources.add(content + "_" + i);
}
} finally
{
writeLock.unlock();//一定要保证锁的释放
}
}
}
========================= 1.3 end
==========================
================= 1.4 ReadWriteLockTest.java
===============
package Executor;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ReadWriteLockTest {
public static void main(String[] args) throws
InterruptedException, ExecutionException {
//1
创建一个具有排程功能的线程池
ScheduledExecutorService service =
Executors.newScheduledThreadPool(5);
//2
读写锁的logic bean
ReadWriteLockLogic lockOperator = new ReadWriteLockLogic();
//3
生成一个可执行任务(该任务执行完毕可以返回结果 或者 抛出异常;而Runnable接口的run方法则不行)
Runnable
writeTask1 = new WriteTask(lockOperator, "作者A");
//4
延时0秒后每2秒重复执行writeTask1;
service.scheduleAtFixedRate(writeTask1, 0, 60,
TimeUnit.SECONDS);
//5
创建3个读任务
Runnable
readTask1 = new ReadTask(lockOperator, "读者A");
Runnable
readTask2 = new ReadTask(lockOperator, "读者B");
Runnable
readTask3 = new ReadTask(lockOperator, "读者C");
//6 延时0秒后
每秒执行一次task1;
service.scheduleAtFixedRate(readTask1, 1, 1,
TimeUnit.SECONDS);
service.scheduleAtFixedRate(readTask2, 2, 1,
TimeUnit.SECONDS);
service.scheduleAtFixedRate(readTask3, 3, 1,
TimeUnit.SECONDS);
}
}
========================= 1.4 end
==========================
输出示例:
作者A write ===Thread[pool-1-thread-1,5,main]
读者C read:Thread[pool-1-thread-3,5,main] :
hehehhe_0
读者B read:Thread[pool-1-thread-4,5,main] :
hehehhe_0
读者A read:Thread[pool-1-thread-2,5,main] :
hehehhe_0
读者C read:Thread[pool-1-thread-3,5,main] :
hehehhe_0
读者B read:Thread[pool-1-thread-4,5,main] :
hehehhe_0
读者B read:Thread[pool-1-thread-4,5,main] :
hehehhe_0
读者C read:Thread[pool-1-thread-3,5,main] :
hehehhe_0
读者A read:Thread[pool-1-thread-2,5,main] :
hehehhe_0
作者A write ===Thread[pool-1-thread-1,5,main]
读者B read:Thread[pool-1-thread-4,5,main] :
hehehhe_0 hehehhe_1
读者C read:Thread[pool-1-thread-3,5,main] :
hehehhe_0 hehehhe_1
一旦有 "作者A write === ..." 在后台输出,表明开始了写操作, 在写过程中读者处于等待中, 后台无输出, 直到写任务执行完毕。