问题描述:
第一次看到这个问题的时候,感觉很简单,不屑于看,然而当我上手敲代码的时候就懵逼了:道理很清楚很明白,可是代码实现确不是那么简单,想了一天都没想通。第二天参考了一篇文章,才理清思路。贴上我认为最简短的而且还能达到题目要求解决所给问题的代码:
//Test.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
public class Test {
/**
* @param args
* 创建了五个线程(四个读,一个写),让它们自己竞争,所以每次运行代码结果是不一样滴。
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Ticket ticket=new Ticket(100);
Mythread mythread1=new Mythread(ticket,"R");
Mythread mythread2=new Mythread(ticket,"R");
Mythread mythread3=new Mythread(ticket,"W");
Mythread mythread4=new Mythread(ticket,"R");
Mythread mythread5=new Mythread(ticket,"R");
mythread1.start();
mythread3.start();
mythread2.start();
mythread4.start();
mythread5.start();
}
}
//Ticket.java
public class Ticket {
private int num;
//标记当前是否有写线程正在执行
private Boolean write=false;
Ticket(){}
Ticket(int n){
this.num=n;
}
public int read(){
System.out.println("====================================");
System.out.println("我是读,我来了");
while(true){
if(this.write){
//如果有写线程正在执行
System.out.println("wait...");
try{wait();}catch (Exception e) {}
}
else{
System.out.println("剩余票数:"+this.num);
break;
}
}
System.out.println("我读完了");
System.out.println("====================================");
return this.num;
}
public synchronized void write(){
this.write=true;//进入写线程,首先改变标记
System.out.println("====================================");
System.out.println("我是写,我来了");
this.num--;
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
System.out.println("修改后的票数:"+this.num);
System.out.println("我写完了");
System.out.println("====================================");
this.write=false;//退出写线程,恢复标记
}
}
//Mythread.java
public class Mythread extends Thread{
Ticket ticket;
public String flag;//标记该线程是读或写
Mythread(Ticket tic,String ch){
this.ticket=tic;
this.flag=ch;
}
@Override
public void run() {
// TODO Auto-generated method stub
if("W".equals(this.flag)){
this.ticket.write();
}
else if("R".equals(this.flag)){
this.ticket.read();
}
}
}
核心代码在Ticket.java类,也不多,哈哈。。
可以看到:当有写操作的时候,无论当前的读操作是否完成,都得进入阻塞,等待写操作完成后,再进行读操作。