【问题阐述】
读者写者问题描述非常简单,有一个写者很多读者,多个读者可以同时读文件,但写者在写文件时不允许有读者在读文件,同样有读者在读文件时写者也不去能写文件。类似于生产者消费者问题的分析过程,首先来找找哪些是属于“等待”情况。
第一.写者要等到没有读者时才能去写文件。
第二.所有读者要等待写者完成写文件后才能去读文件。
【结果演示】
【详细代码】
Book.java
package com.anqi.thread;
class Book {
// readCount表示正在读的人数,初值为0,表示还没有人读。
private int readerCount;
// doreading表示读信号量,当doreading=true时不能进行写操作。
private boolean doreading;
// dowriting表示写信号量,当dowriting=ture时不能进行读操作。
private boolean dowriting;
public Book() {
readerCount = 0;
doreading = false;
dowriting = false;
}
// 线程睡眠,不消耗CPU资源
public static void naps() {
try {
Thread.sleep((int) (4000 * Math.random()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized int startRead() {
// 开始读操作
while (dowriting == true) {
try {
System.out.println(Thread.currentThread().getName()+" is waiting");
// 等待写者发出notify
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+" begin to read!");
readerCount++;
if (readerCount == 1) {
doreading = true;
}
return readerCount;
}
public synchronized int endRead() {
// 结束读操作
--readerCount;
if (readerCount == 0) {
doreading = false;
}
notifyAll();
System.out.println(Thread.currentThread().getName()+" reading done!");
return readerCount;
}
public synchronized void startWrite() {
// 开始写操作
while (doreading == true || dowriting == true) {
try {
System.out.println(Thread.currentThread().getName()+" is waiting");
wait();
// 等待写者或读者发出notify
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+" begin to write!");
dowriting = true;
}
public synchronized void endWrite() {
// 结束写操作
dowriting = false;
notifyAll();
System.out.println(Thread.currentThread().getName()+" writing done!");
}
}
Reader.java
package com.anqi.thread;
class Reader implements Runnable {
private int readerNum;
private Book df;
public Reader(int readerNum, Book df) {
this.readerNum = readerNum;
this.df = df;
}
public void run() {
//while (true) {
System.out.println("reader " + readerNum + " comes here");
df.naps();
df.startRead();
df.naps();
df.endRead();
//}
}
}
Writer.java
package com.anqi.thread;
class Writer implements Runnable {
private Book df;
private int writerNum;
public Writer(int writerNum, Book df) {
this.df = df;
this.writerNum = writerNum;
}
public void run() {
//while (true) {
System.out.println("Writer " + writerNum + " comes here");
df.naps();
df.startWrite();
df.naps();
df.endWrite();
//}
}
}
Main.java
package com.anqi.thread;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JTextArea;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JTextField;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Main extends JFrame {
private JPanel contentPane;
Book df = new Book();
private static int countReader = 1;
private static int countWriter = 1;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Main frame = new Main();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Main() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 306, 212);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JButton addReader = new JButton("\u589E\u52A0\u8BFB\u8005");
addReader.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
new Thread(new Reader(countReader, df), "读者线程 "+countReader++).start();
//增加读者
}
});
addReader.setBounds(97, 107, 93, 23);
contentPane.add(addReader);
JButton addWriter = new JButton("\u589E\u52A0\u5199\u8005");
addWriter.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
//增加写者
new Thread(new Writer(countWriter, df), "写者线程"+countWriter++).start();
}
});
addWriter.setBounds(97, 46, 93, 23);
contentPane.add(addWriter);
this.setLocationRelativeTo(null);
}
}