在0和1的世界里,线程们的发展史凝结了血与泪...
线程一族在由无到有、由有到优的进化过程中,遭遇过很多挫折、磨难和困难。
曾几何时,线程一族内部硝烟四起,纷争不断。
为了建设更加富强、民主、文明、和谐的零壹世界,线程拉比们对关于不同肤色不同种族的线程如何和平共处的课题进行了广泛地探讨。
在和平共处这一宏大课题中的一个不很起眼的小问题,就是线程中广为流传的“读写者问题”。
读者,其抽象对象是只需要读取数据的线程;与之对应,写者,就是可以进行读写操作的线程。
众所周知,多个读者一起读数据完全ok,但不允许多个写者一起写数据(不然写的是个球?),且,不允许读者和写者对数据同时进行操作(不然读者会疯掉)。所以和谐的情形是,要么一个或几个读者同时读数据,要么只有一个写者在写数据,要么数据处于不被访问的状态。
如何制定线程们的行为准则(编写线程的内部代码)去让两种线程遵守这样的规则从而使得读写线程们和谐地一起做事(并发执行)呢?
聪明的拉比们想到了线程世界的灯塔--信号量(Semaphore)。
信号量可以标识一种状态,而某个线程能否不违背规则地执行需要看环境的状态(有没有读者读啦,有没有写者写啦,有没有排队到自己啦等等)。因此,信号量理所应当地成为了线程们一起和谐做事的控制灯。
线程的先驱者按照实现思路及难易程度来依次制定了(实现了)三种解决读写者问题的规则(算法):“读者优先”->“公平竞争”->“写者优先”。
咳咳... 谈正事。
1.“读者优先算法”
为了使得读者和写者互不冲突,且写者之间互不冲突,我们定义了一个信号量-“读写锁”(wrt),这足够了;
由于读者可以多个,我们需要记录读者数量,为了记录读者的数量,我们定义了readcount,有了readcount我们需要对readcount进行加减操作,而readcount本身是一个共享数据,为了使得各个读线程在对readcount进行操作时互不冲突,我们定义了一个信号量-“改数锁”(mutex)。
下面我们利用上述信号量去模拟实现读写者问题中的读线程、写线程、共享数据(注意看注释,这里不详细写了):
import java.util.concurrent.Semaphore; //ShareData.java
public class SharedData {
public Semaphore mutex = new Semaphore(1);//确保更新“读者数”时的互斥(姑且称之为“改数锁”)->必要锁
//initialized to 1, used to ensure mutual exclusion when the variable readcount is updated.
public Semaphore wrt = new Semaphore(1);//确保最多只能有一个写者(姑且称之为“读写锁”)->核心锁
//initialized to 1, common to both the reader and writer processes, used as a mutual exclusion semaphore for the writer.
public int readcount = 0;//写者数
//initialized to 0, keeps track of how many processes are reading the object.
public String fileName = "hello"; //模拟数据库
}
import java.io.BufferedReader; //Reader.java
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
public class Reader implements Runnable {
SharedData sharedData;
public Reader(SharedData sharedData) {
super(); //继承父类的run()
this.sharedData = sharedData;
}
public void read() { //按照行从hello中读取文件,并显示到控制台
try {
FileInputStream fis = new FileInputStream(sharedData.fileName);
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
String s;
try {
while ((s = br.readLine()) != null) {
System.out.println("Reader " + Thread.currentThread().getName() + ": " + s);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void run() {
while (true) {
try {
sharedData.mutex.acquire();//为改“读者数”加锁
sharedData.readcount++;
if (sharedData.readcount == 1)//如果此时读者数为1,那么为“不让写者进入”加锁
sharedData.wrt.acquire();