实现招生录取系统中的部分功能(使用main方法作为程序入口)
1. 读XML文件,进过程序处理后,总成绩按降序排序,结果通过IO流输出到result_1.txt文件中。如:
班级[className classID]
学员姓名 学员ID[总分:457,学科ID:87,学科ID:83,学科ID:82,学科ID:83]
学员姓名 学员ID[总分:453,学科ID:87,学科ID:83,学科ID:82,学科ID:83]
学员姓名 学员ID[总分:448,学科ID:87,学科ID:83,学科ID:82,学科ID:83]
班级[className classID]
学员姓名 学员ID[总分:457,学科ID:87,学科ID:83,学科ID:82,学科ID:83]
学员姓名 学员ID[总分:454,学科ID:87,学科ID:83,学科ID:82,学科ID:83]
学员姓名 学员ID[总分:445,学科ID:87,学科ID:83,学科ID:82,学科ID:83]
说明:
className classID用空格隔开,className为班级名称,classID为班级编号。
学员姓名 学员ID用空格隔开,每位学员成绩独占一行。总分为学员各学科成绩之和。
2. 通过IO读result_1.txt文件,以多线程方式实现大学录取学生功能
大学列表:清华大学、北京大学、南京大学、复旦大学、南京职业技术学院
说明:
A类大学为清华大学、北京大学,分数线为340,名额各为3名,;
B类大学为南京大学、复旦大学,分数线为320,名额各为10名;;
C类大学为南京职业技术学院,分数线为250,名额不限;
分数超过名额应该取最高分;达不到分数线可以不录取;
录取按大学类别进行:先A类,再B类,最后C类;
同类大学之间可以抢学生,同一学生只能被一所大学录取,以先录取为准;
结果通过IO输出result_2.txt,如:
清华大学:
学员姓名 学员ID[总分:457,学科ID:87,学科ID:83,学科ID:82,学科ID:83]
北京大学:学员姓名 学员ID[总分:448,学科ID:87,学科ID:83,学科ID:82,学科ID:83]
南京大学:学员姓名 学员ID[总分:448,学科ID:87,学科ID:83,学科ID:82,学科ID:83]
复旦大学:学员姓名 学员ID[总分:448,学科ID:87,学科ID:83,学科ID:82,学科ID:83]
南京职业技术学院:学员姓名 学员ID[总分:448,学科ID:87,学科ID:83,学科ID:82,学科ID:83]
未被录取学员:
学员姓名 学员ID[总分:128],学员姓名 学员ID[总分:215]
xml文档如下:
<root>
<!--表结构-->
<tables>
<!--学员表-->
<table id="1000" name="studentTbl">
<fields>
<field id="studentId" /><!--学号-->
<field id="name" /><!--姓名-->
<field id="sex "/><!--性别-->
</fields>
</table>
<!--班级表-->
<table id="1001" name="classTbl">
<fields>
<field id="classId" /><!--班级编号-->
<field id="name" /><!--班级名称-->
</fields>
</table>
<!--班级学员表-->
<table id="1004" name="classStudentTbl">
<fields>
<field id="classId" /><!--班级编号-->
<field id="studentId" /><!--学号-->
</fields>
</table>
<!--学科表-->
<table id="1002" name="subjectTbl">
<fields>
<field id="subjectId" /><!--学科编号-->
<field id="name" /><!--学科名称-->
</fields>
</table>
<!--成绩表-->
<table id="1003" name="scoreTbl">
<fields>
<field id="studentId" /><!--学号-->
<field id="subjectId" /><!--学科编号-->
<field id="score" /><!--成绩-->
</fields>
</table>
</tables>
<!--数据信息,字段值以','分隔-->
<datas>
<!--学员数据-->
<data tableid="1000">
<fields-data>st001,张一,男</fields-data>
<fields-data>st002,李二,男</fields-data>
<fields-data>st003,王三,女</fields-data>
<fields-data>st004,杨四,男</fields-data>
<fields-data>st005,赵五,男</fields-data>
<fields-data>st006,郑陆,女</fields-data>
<fields-data>st007,林世,男</fields-data>
<fields-data>st008,胡长,男</fields-data>
<fields-data>st009,邹家,男</fields-data>
<fields-data>st010,李方,男</fields-data>
<fields-data>st011,宁可,男</fields-data>
<fields-data>st012,张杂,男</fields-data>
<fields-data>st013,李度,男</fields-data>
<fields-data>st014,王等,女</fields-data>
<fields-data>st015,杨角,男</fields-data>
<fields-data>st016,赵度,男</fields-data>
<fields-data>st017,郑来,男</fields-data>
<fields-data>st018,林衡,男</fields-data>
<fields-data>st019,胡量,男</fields-data>
<fields-data>st020,邹代,女</fields-data>
<fields-data>st021,李码,男</fields-data>
<fields-data>st022,宁的,男</fields-data>
<fields-data>st023,张质,男</fields-data>
</data>
<!--班级数据-->
<data tableid="1001">
<fields-data>1,一年级</fields-data>
<fields-data>2,二年级</fields-data>
<fields-data>3,三年级</fields-data>
</data>
<!--学员班级信息-->
<data tableid="1004">
<fields-data>1,st001</fields-data>
<fields-data>2,st002</fields-data>
<fields-data>3,st003</fields-data>
<fields-data>1,st004</fields-data>
<fields-data>2,st005</fields-data>
<fields-data>3,st006</fields-data>
<fields-data>1,st007</fields-data>
<fields-data>2,st008</fields-data>
<fields-data>3,st009</fields-data>
<fields-data>2,st010</fields-data>
<fields-data>3,st011</fields-data>
<fields-data>3,st012</fields-data>
<fields-data>1,st013</fields-data>
<fields-data>1,st014</fields-data>
<fields-data>2,st015</fields-data>
<fields-data>3,st016</fields-data>
<fields-data>3,st017</fields-data>
<fields-data>2,st018</fields-data>
<fields-data>1,st019</fields-data>
<fields-data>1,st020</fields-data>
<fields-data>2,st021</fields-data>
<fields-data>3,st022</fields-data>
<fields-data>2,st023</fields-data>
<fields-data>3,st024</fields-data>
</data>
<!--学科数据-->
<data tableid="1002">
<fields-data>1,英语</fields-data>
<fields-data>2,化学</fields-data>
<fields-data>3,代数</fields-data>
<fields-data>4,计算机</fields-data>
</data>
<!--成绩数据-->
<data tableid="1003">
<fields-data>st001,1,80</fields-data>
<fields-data>st001,2,90</fields-data>
<fields-data>st001,3,70</fields-data>
<fields-data>st001,4,100</fields-data>
<fields-data>st002,1,77</fields-data>
<fields-data>st002,2,88</fields-data>
<fields-data>st002,3,99</fields-data>
<fields-data>st002,4,56</fields-data>
<fields-data>st003,1,96</fields-data>
<fields-data>st003,2,56</fields-data>
<fields-data>st003,3,88</fields-data>
<fields-data>st003,4,69</fields-data>
<fields-data>st004,1,78</fields-data>
<fields-data>st004,2,85</fields-data>
<fields-data>st004,3,83</fields-data>
<fields-data>st004,4,96</fields-data>
<fields-data>st005,1,79</fields-data>
<fields-data>st005,2,87</fields-data>
<fields-data>st005,3,91</fields-data>
<fields-data>st005,4,85</fields-data>
<fields-data>st006,1,79</fields-data>
<fields-data>st006,2,87</fields-data>
<fields-data>st006,3,68</fields-data>
<fields-data>st006,4,86</fields-data>
<fields-data>st007,1,55</fields-data>
<fields-data>st007,2,78</fields-data>
<fields-data>st007,3,90</fields-data>
<fields-data>st007,4,68</fields-data>
<fields-data>st008,1,69</fields-data>
<fields-data>st008,2,86</fields-data>
<fields-data>st008,3,75</fields-data>
<fields-data>st008,4,69</fields-data>
<fields-data>st009,1,84</fields-data>
<fields-data>st009,2,69</fields-data>
<fields-data>st009,3,90</fields-data>
<fields-data>st009,4,49</fields-data>
<fields-data>st010,1,77</fields-data>
<fields-data>st010,2,86</fields-data>
<fields-data>st010,3,99</fields-data>
<fields-data>st010,4,82</fields-data>
<fields-data>st011,1,67</fields-data>
<fields-data>st011,2,87</fields-data>
<fields-data>st011,3,69</fields-data>
<fields-data>st011,4,56</fields-data>
<fields-data>st012,1,44</fields-data>
<fields-data>st012,2,66</fields-data>
<fields-data>st012,3,99</fields-data>
<fields-data>st012,4,89</fields-data>
<fields-data>st013,1,67</fields-data>
<fields-data>st013,2,87</fields-data>
<fields-data>st013,3,78</fields-data>
<fields-data>st013,4,78</fields-data>
<fields-data>st014,1,56</fields-data>
<fields-data>st014,2,78</fields-data>
<fields-data>st014,3,88</fields-data>
<fields-data>st014,4,11</fields-data>
<fields-data>st015,1,0</fields-data>
<fields-data>st015,2,44</fields-data>
<fields-data>st015,3,66</fields-data>
<fields-data>st015,4,99</fields-data>
<fields-data>st016,1,67</fields-data>
<fields-data>st016,2,98</fields-data>
<fields-data>st016,3,78</fields-data>
<fields-data>st016,4,99</fields-data>
<fields-data>st017,1,89</fields-data>
<fields-data>st017,2,88</fields-data>
<fields-data>st017,3,90</fields-data>
<fields-data>st017,4,96</fields-data>
<fields-data>st018,1,93</fields-data>
<fields-data>st018,2,95</fields-data>
<fields-data>st018,3,96</fields-data>
<fields-data>st018,4,91</fields-data>
<fields-data>st019,1,98</fields-data>
<fields-data>st019,2,94</fields-data>
<fields-data>st019,3,93</fields-data>
<fields-data>st019,4,89</fields-data>
<fields-data>st020,1,87</fields-data>
<fields-data>st020,2,96</fields-data>
<fields-data>st020,3,79</fields-data>
<fields-data>st020,4,82</fields-data>
<fields-data>st021,1,77</fields-data>
<fields-data>st021,2,87</fields-data>
<fields-data>st021,3,89</fields-data>
<fields-data>st021,4,86</fields-data>
<fields-data>st022,1,94</fields-data>
<fields-data>st022,2,76</fields-data>
<fields-data>st022,3,69</fields-data>
<fields-data>st022,4,79</fields-data>
<fields-data>st023,1,87</fields-data>
<fields-data>st023,2,57</fields-data>
<fields-data>st023,3,48</fields-data>
<fields-data>st023,4,48</fields-data>
<fields-data>st024,1,56</fields-data>
<fields-data>st024,2,68</fields-data>
<fields-data>st024,3,78</fields-data>
<fields-data>st024,4,81</fields-data>
<fields-data>st025,1,99</fields-data>
<fields-data>st025,2,47</fields-data>
<fields-data>st025,3,68</fields-data>
<fields-data>st025,4,98</fields-data>
<fields-data>st026,1,69</fields-data>
<fields-data>st026,2,95</fields-data>
<fields-data>st026,3,75</fields-data>
<fields-data>st026,4,95</fields-data>
<fields-data>st027,1,84</fields-data>
<fields-data>st027,2,85</fields-data>
<fields-data>st027,3,96</fields-data>
<fields-data>st027,4,76</fields-data>
<fields-data>st028,1,83</fields-data>
<fields-data>st028,2,95</fields-data>
</data>
</datas>
</root>
实现:
import java.util.Set;
import java.util.TreeSet;
/**
* 班级类
*/
public class Class implements Comparable<Class>
{
private int classId;
private String name;
//维护本班级下面所有的student
private Set<Student> students;
public Class()
{
//有序存储student对象
students = new TreeSet<Student>();
}
public Class(int classId, String name)
{
this();
this.classId = classId;
this.name = name;
}
public void setStudents(Set<Student> students)
{
this.students = students;
}
public Set<Student> getStudents()
{
return students;
}
public int getClassId()
{
return classId;
}
public void setClassId(int classId)
{
this.classId = classId;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
@Override
public String toString()
{
return "班级[" + name + " " + classId + "]";
}
@Override
public int compareTo(Class o)
{
return classId - o.classId;
}
}
import java.util.Set;
import java.util.TreeSet;
/**
* 学生类
*/
public class Student implements Comparable<Student>
{
private String studentId;
private String name;
private String sex;
private Set<Score> scores;
public Student()
{
scores = new TreeSet<Score>();
}
public Student(String studentId, String name, String sex)
{
this();
this.studentId = studentId;
this.name = name;
this.sex = sex;
}
public Set<Score> getScores()
{
return scores;
}
public void setScores(Set<Score> scores)
{
this.scores = scores;
}
public String getStudentId()
{
return studentId;
}
public void setStudentId(String studentId)
{
this.studentId = studentId;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getSex()
{
return sex;
}
public void setSex(String sex)
{
this.sex = sex;
}
//按总成绩对学生排序,如果总成绩相同,按学号排序
@Override
public int compareTo(Student o)
{
float total = 0f;
for (Score score : scores)
total += score.getScore();
float o_total = 0f;
for (Score score : o.getScores())
o_total += score.getScore();
int result = (int) (o_total - total);
if (result != 0)
return result;
return studentId.compareTo(o.studentId);
}
@Override
public String toString()
{
StringBuilder result = new StringBuilder();
result.append(name).append(' ').append(studentId).append("[总分:%3d, ");
float total = 0f;
for (Score score : scores)
{
result.append(score.getCourse().getName()).append(":").append(String.format("%3d", (int) score.getScore()))
.append(", ");
total += score.getScore();
}
return String.format(result.substring(0, result.length() - 2) + "]", (int) total);
}
}
/**
* 成绩类
*/
public class Score implements Comparable<Score>
{
private float score;
private Student student;
private Course course;
public Score(float score, Student student, Course course)
{
this.score = score;
this.student = student;
this.course = course;
}
public Score()
{
}
public float getScore()
{
return score;
}
public void setScore(float score)
{
this.score = score;
}
public Student getStudent()
{
return student;
}
public void setStudent(Student student)
{
this.student = student;
}
public Course getCourse()
{
return course;
}
public void setCourse(Course course)
{
this.course = course;
}
//按课程号进行排序
@Override
public int compareTo(Score o)
{
return course.getSujectId() - o.course.getSujectId();
}
}
/**
* 课程类
*/
public class Course
{
private int sujectId;
private String name;
public Course()
{
}
public Course(int sujectId, String name)
{
this.sujectId = sujectId;
this.name = name;
}
public int getSujectId()
{
return sujectId;
}
public void setSujectId(int sujectId)
{
this.sujectId = sujectId;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
import java.io.IOException;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
*
* 解析xml文档的工具类
*/
public class DataParser
{
//定义解析数据过程中需要用到的一些常量数据
private static final String DATA_ELEMENT = "data";
private static final String FIELD_DATA_ELEMENT = "fields-data";
private static final String TABLE_ID_ATTRIBUTE = "tableid";
private static final String STUDENT_DATA = "1000";
private static final String CLASS_DATA = "1001";
private static final String COURSE_DATA = "1002";
private static final String SCORE_DATA = "1003";
private static final String STUDENT_CLASS_DATA = "1004";
public static void main(String[] args)
{
Set<Class> classes = getClasses("src/data.xml");
PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream("result_1.txt"), "UTF-8"), true);
for (Class cls : classes)
{
writer.println(cls);
for (Student student : cls.getStudents())
{
writer.println(student);
}
}
writer.close();
}
public static Set<Class> getClasses(String filePath)
{
DocumentBuilderFactory parserFactory = DocumentBuilderFactory.newInstance();
//解析完成的数据 暂时存储在map集合中 方便查找
HashMap<Integer, Class> cls_map = new HashMap<Integer, Class>();
HashMap<String, Student> stu_map = new HashMap<String, Student>();
HashMap<Integer, Course> cour_map = new HashMap<Integer, Course>();
try
{
DocumentBuilder parser = parserFactory.newDocumentBuilder();
Document doc = parser.parse(filePath);
XPath xpath = XPathFactory.newInstance().newXPath();
//xpath表达式 %s表示待替换的属性值
String expr = "//" + DATA_ELEMENT + "[@" + TABLE_ID_ATTRIBUTE + "=%s]";
//解析class数据
Element cls_elt = (Element) xpath.compile(String.format(expr, CLASS_DATA)).evaluate(doc, XPathConstants.NODE);
NodeList cls_items = cls_elt.getElementsByTagName(FIELD_DATA_ELEMENT);
for (int i = 0; i < cls_items.getLength(); i++)
{
String item = cls_items.item(i).getTextContent();
String[] parts = item.split(",");
if (parts.length != 2)
throw new IllegalArgumentException("invalid class data item: " + item);
int classId = Integer.parseInt(parts[0].trim());
String name = parts[1].trim();
cls_map.put(classId, new Class(classId, name));
}
//解析student数据
Element stu_elt = (Element) xpath.compile(String.format(expr, STUDENT_DATA)).evaluate(doc, XPathConstants.NODE);
NodeList stu_items = stu_elt.getElementsByTagName(FIELD_DATA_ELEMENT);
for (int i = 0; i < stu_items.getLength(); i++)
{
String item = stu_items.item(i).getTextContent();
String[] parts = item.split(",");
if (parts.length != 3)
throw new IllegalArgumentException("invalid student data item: " + item);
String studentId = parts[0].trim();
String name = parts[1].trim();
String sex = parts[2].trim();
stu_map.put(studentId, new Student(studentId, name, sex));
}
//解析course数据
Element cour_elt = (Element) xpath.compile(String.format(expr, COURSE_DATA)).evaluate(doc, XPathConstants.NODE);
NodeList cour_items = cour_elt.getElementsByTagName(FIELD_DATA_ELEMENT);
for (int i = 0; i < cour_items.getLength(); i++)
{
String item = cour_items.item(i).getTextContent();
String[] parts = item.split(",");
if (parts.length != 2)
throw new IllegalArgumentException("invalid course data item: " + item);
int courseId = Integer.parseInt(parts[0].trim());
String name = parts[1].trim();
cour_map.put(courseId, new Course(courseId, name));
}
//解析score数据
Element score_elt = (Element) xpath.compile(String.format(expr, SCORE_DATA)).evaluate(doc, XPathConstants.NODE);
NodeList score_items = score_elt.getElementsByTagName(FIELD_DATA_ELEMENT);
Score score;
for (int i = 0; i < score_items.getLength(); i++)
{
String item = score_items.item(i).getTextContent();
String[] parts = item.split(",");
if (parts.length != 3)
throw new IllegalArgumentException("invalid score data item: " + item);
String studentId = parts[0].trim();
Student stu = stu_map.get(studentId);
if (stu == null)
{
System.out.println("invalid student id: " + studentId);
continue;
}
int courseId = Integer.parseInt(parts[1].trim());
Course cour = cour_map.get(courseId);
if (cour == null)
{
System.out.println("invalid course id: " + courseId);
continue;
}
float grade = Float.parseFloat(parts[2].trim());
score = new Score();
score.setScore(grade);
score.setCourse(cour);
score.setStudent(stu);
stu.getScores().add(score);
}
//解析class-student数据
Element stu_cls_elt = (Element) xpath.compile(String.format(expr, STUDENT_CLASS_DATA)).evaluate(doc,
XPathConstants.NODE);
NodeList stu_cls_items = stu_cls_elt.getElementsByTagName(FIELD_DATA_ELEMENT);
for (int i = 0; i < stu_cls_items.getLength(); i++)
{
String item = stu_cls_items.item(i).getTextContent();
String[] parts = item.split(",");
if (parts.length != 2)
throw new IllegalArgumentException("invalid class to student mapping data item: " + item);
int classId = Integer.parseInt(parts[0].trim());
String studentId = parts[1].trim();
Class cls = cls_map.get(classId);
if (cls == null)
{
System.out.println("invalid class id: " + classId);
continue;
}
Student stu = stu_map.get(studentId);
if (stu == null)
{
System.out.println("invalid student id: " + studentId);
continue;
}
cls.getStudents().add(stu);
}
}
catch (ParserConfigurationException e)
{
throw new RuntimeException("parser configuration error", e);
}
catch (SAXException e)
{
throw new RuntimeException("parse error", e);
}
catch (IOException e)
{
throw new RuntimeException("io operation error", e);
}
catch (XPathExpressionException e)
{
throw new RuntimeException("xpath expression error", e);
}
//最终将class数据存储到treemap集合返回
return new TreeSet<Class>(cls_map.values());
}
}
-------------------执行结果 result_1.txt-------------------------
班级[一年级 1]
胡量 st019[总分:374, 英语: 98, 化学: 94, 代数: 93, 计算机: 89]
邹代 st020[总分:344, 英语: 87, 化学: 96, 代数: 79, 计算机: 82]
杨四 st004[总分:342, 英语: 78, 化学: 85, 代数: 83, 计算机: 96]
张一 st001[总分:340, 英语: 80, 化学: 90, 代数: 70, 计算机:100]
李度 st013[总分:310, 英语: 67, 化学: 87, 代数: 78, 计算机: 78]
林世 st007[总分:291, 英语: 55, 化学: 78, 代数: 90, 计算机: 68]
王等 st014[总分:233, 英语: 56, 化学: 78, 代数: 88, 计算机: 11]
班级[二年级 2]
林衡 st018[总分:375, 英语: 93, 化学: 95, 代数: 96, 计算机: 91]
李方 st010[总分:344, 英语: 77, 化学: 86, 代数: 99, 计算机: 82]
赵五 st005[总分:342, 英语: 79, 化学: 87, 代数: 91, 计算机: 85]
李码 st021[总分:339, 英语: 77, 化学: 87, 代数: 89, 计算机: 86]
李二 st002[总分:320, 英语: 77, 化学: 88, 代数: 99, 计算机: 56]
胡长 st008[总分:299, 英语: 69, 化学: 86, 代数: 75, 计算机: 69]
张质 st023[总分:240, 英语: 87, 化学: 57, 代数: 48, 计算机: 48]
杨角 st015[总分:209, 英语: 0, 化学: 44, 代数: 66, 计算机: 99]
班级[三年级 3]
郑来 st017[总分:363, 英语: 89, 化学: 88, 代数: 90, 计算机: 96]
赵度 st016[总分:342, 英语: 67, 化学: 98, 代数: 78, 计算机: 99]
郑陆 st006[总分:320, 英语: 79, 化学: 87, 代数: 68, 计算机: 86]
宁的 st022[总分:318, 英语: 94, 化学: 76, 代数: 69, 计算机: 79]
王三 st003[总分:309, 英语: 96, 化学: 56, 代数: 88, 计算机: 69]
张杂 st012[总分:298, 英语: 44, 化学: 66, 代数: 99, 计算机: 89]
邹家 st009[总分:292, 英语: 84, 化学: 69, 代数: 90, 计算机: 49]
宁可 st011[总分:279, 英语: 67, 化学: 87, 代数: 69, 计算机: 56]
public class SelectStudent
{
//构建一个简单的Student类,存储从txt文件解析出来的Student对象
static class SimpleStudent implements Comparable<SimpleStudent>
{
//总成绩
private int score;
//考生详细信息
private String info;
public SimpleStudent()
{
}
public SimpleStudent(int score, String info)
{
this.score = score;
this.info = info;
}
public int getScore()
{
return score;
}
public void setScore(int score)
{
this.score = score;
}
public String getInfo()
{
return info;
}
public void setInfo(String info)
{
this.info = info;
}
//按总成绩排序,如果总成绩相同,按详细信息排序
@Override
public int compareTo(SimpleStudent o)
{
int result = o.score - score;
if (result != 0)
return result;
return info.compareTo(o.info);
}
@Override
public String toString()
{
return info;
}
}
private final Lock lock = new ReentrantLock();
//A类线程等待的信号
private final Condition con_a = lock.newCondition();
//B类线程等待的信号
private final Condition con_b = lock.newCondition();
//C类线程等待的信号
private final Condition con_c = lock.newCondition();
//使用一个线程池运行相关的Task
private ExecutorService executor = Executors.newCachedThreadPool();
private int state = 0;
public SelectStudent()
{
}
public void shutdownExecutorNow()
{
if (!executor.isShutdown())
executor.shutdownNow();
}
//线程管理类
abstract class Monitor implements Runnable
{
CountDownLatch cdl_before;
CountDownLatch cdl_after;
Monitor(CountDownLatch cdl_before, CountDownLatch cdl_after)
{
this.cdl_before = cdl_before;
this.cdl_after = cdl_after;
}
@Override
public void run()
{
//获得锁
lock.lock();
try
{
//具体实现由子类完成
process();
}
catch (InterruptedException e)
{
throw new RuntimeException("interrupted error", e);
}
finally
{
//释放锁
lock.unlock();
}
}
abstract void process() throws InterruptedException;
}
//A类管理线程
class MonitorA extends Monitor
{
MonitorA(CountDownLatch cdl_before, CountDownLatch cdl_after)
{
super(cdl_before, cdl_after);
}
@Override
void process() throws InterruptedException
{
//当state=0 表明当前状态允许执行
while (state % 3 != 0)
//若条件不符合,在con_a条件上等待
con_a.await();
//通知A类线程开始执行
cdl_before.countDown();
//等待所有A类线程执行完成
cdl_after.await();
state++;
//通知B类管理线程开始执行
con_b.signal();
}
}
//B类管理线程
class MonitorB extends Monitor
{
MonitorB(CountDownLatch cdl_before, CountDownLatch cdl_after)
{
super(cdl_before, cdl_after);
}
@Override
void process() throws InterruptedException
{
//state=1 允许执行
while (state % 3 != 1)
//若条件不符合,在con_b条件上等待
con_b.await();
//通知B类线程开始执行
cdl_before.countDown();
//等待所有B类线程执行完成
cdl_after.await();
state++;
//通知C类管理线程开始执行
con_c.signal();
}
}
//C类管理线程
class MonitorC extends Monitor
{
MonitorC(CountDownLatch cdl_before, CountDownLatch cdl_after)
{
super(cdl_before, cdl_after);
}
@Override
void process() throws InterruptedException
{
//state=2 运行执行
while (state % 3 != 2)
//若条件不符合,在con_c条件上等待
con_c.await();
//通知所有C类线程执行
cdl_before.countDown();
}
}
//模拟TimeUnit.unit.sleep 非阻塞方法
void sleep(TimeUnit unit, long duration)
{
long startTime = System.nanoTime();
while (System.nanoTime() - startTime < unit.toNanos(duration))
{
}
}
//录取考生线程(A类,B类,C类)
class SelectTask implements Runnable
{
//学校名称
private String name;
//录取人数
private int num;
//分数线
private int grade;
//考生列表
private List<SimpleStudent> students;
//消息队列
private ConcurrentLinkedQueue<String> queue;
//任务开始条件
private CountDownLatch cdl_before;
//任务结束条件
private CountDownLatch cdl_after;
SelectTask(String schoolName, List<SimpleStudent> stus, ConcurrentLinkedQueue<String> queue, int selectNum, int grade,
CountDownLatch cdl_before, CountDownLatch cdl_after)
{
name = schoolName;
students = stus;
num = selectNum;
this.grade = grade;
this.queue = queue;
this.cdl_before = cdl_before;
this.cdl_after = cdl_after;
}
@Override
public void run()
{
try
{
//等待任务开始条件
cdl_before.await();
SimpleStudent student;
int i = 0;
try
{
//开始录取操作
for (i = 0; i < num; i++)
{
sleep(TimeUnit.MILLISECONDS, 5);
synchronized (students)
{
//如果学校列表已经为空,强制终止整个录取过程(强制关闭线程池)
if (students.isEmpty())
{
queue.offer(name + ": 没有可录取的学生!");
shutdownExecutorNow();
return;
}
student = students.get(0);
//如果没有达到分数线,终止录取过程
if (student.getScore() < grade)
break;
//将录取信息加入到消息队列
queue.offer(name + ": " + students.remove(0).info);
}
}
}
finally
{
//将统计消息加入消息队列
//放在finally中,即使强制终止当前线程,也会执行该语句
queue.offer(name + ":[" + ((num == i || num == Integer.MAX_VALUE) ? "达标" : "未达标") + "] 当前录取" + i + "/总名额"
+ (num == Integer.MAX_VALUE ? "(无限制)" : num));
}
}
catch (InterruptedException e)
{
throw new RuntimeException("interrupted error", e);
}
finally
{
//当前任务运行结束
cdl_after.countDown();
}
}
}
//打印未被录取考生信息的线程
class NotSelectTask implements Runnable
{
//考生列表
private List<SimpleStudent> students;
//消息队列
private ConcurrentLinkedQueue<String> queue;
//任务开始条件
private CountDownLatch cdl;
public NotSelectTask(List<SimpleStudent> students, ConcurrentLinkedQueue<String> queue, CountDownLatch cdl)
{
this.students = students;
this.queue = queue;
this.cdl = cdl;
}
@Override
public void run()
{
try
{
//等待任务开始条件(所有C类线程执行完毕)
cdl.await();
while (!students.isEmpty())
//将未被录取考生信息加入消息队列
queue.offer("未被录取:" + students.remove(0).info);
//终止线程池
executor.shutdown();
}
catch (InterruptedException e)
{
throw new RuntimeException("wait interrupted", e);
}
}
}
//消息处理线程 从消息队列取出消息,通过输出流写到文件中
class OutputTask implements Runnable
{
private ConcurrentLinkedQueue<String> queue;
private PrintWriter writer;
OutputTask(ConcurrentLinkedQueue<String> queue, String outFile)
{
this.queue = queue;
try
{
writer = new PrintWriter(new FileOutputStream(outFile));
}
catch (FileNotFoundException e)
{
throw new RuntimeException(e);
}
}
@Override
public void run()
{
String content = null;
while (true)
{
//如果录取线程池已经终止且当前消息队列为空,退出
if (executor.isTerminated() && queue.isEmpty())
break;
content = queue.poll();
if (content != null)
writer.println(content);
writer.flush();
}
writer.close();
}
}
public static void main(String[] args) throws Exception
{
SelectStudent ss = new SelectStudent();
List<SimpleStudent> stus = ss.parseTextFile("result_1.txt");
ss.select(stus);
}
public void select(List<SimpleStudent> list)
{
//消息队列
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<String>();
//构建消息处理线程
new Thread(new OutputTask(queue, "result_2.txt")).start();
CountDownLatch cdl_11 = new CountDownLatch(1);
CountDownLatch cdl_21 = new CountDownLatch(2);
//A类管理线程
executor.execute(new MonitorA(cdl_11, cdl_21));
//A类线程
executor.execute(new SelectTask("清华大学", list, queue, 3, 340, cdl_11, cdl_21));
//A类线程
executor.execute(new SelectTask("北京大学", list, queue, 3, 340, cdl_11, cdl_21));
CountDownLatch cdl_12 = new CountDownLatch(1);
CountDownLatch cdl_22 = new CountDownLatch(2);
//B类管理线程
executor.execute(new MonitorB(cdl_12, cdl_22));
//B类线程
executor.execute(new SelectTask("南京大学", list, queue, 10, 320, cdl_12, cdl_22));
//B类线程
executor.execute(new SelectTask("复旦大学", list, queue, 10, 320, cdl_12, cdl_22));
CountDownLatch cdl_13 = new CountDownLatch(1);
CountDownLatch cdl_23 = new CountDownLatch(1);
//C类管理线程
executor.execute(new MonitorC(cdl_13, cdl_23));
//C类线程
executor.execute(new SelectTask("南京职业技术学院", list, queue, Integer.MAX_VALUE, 250, cdl_13, cdl_23));
//处理未被录取考生线程
executor.execute(new NotSelectTask(list, queue, cdl_23));
}
//从txt文档解析考生信息,并按总成绩进行排序
public List<SimpleStudent> parseTextFile(String filename) throws Exception
{
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(filename), "UTF-8"));
String line = null;
List<SimpleStudent> students = new ArrayList<SimpleStudent>();
SimpleStudent stu;
while (null != (line = reader.readLine()))
{
int index = line.indexOf("总分");
if (index == -1)
continue;
String score_str = line.substring(index + 3, line.indexOf(",", index));
stu = new SimpleStudent(Integer.parseInt(score_str), line);
students.add(stu);
}
Collections.sort(students);
return students;
}
}
-------------------执行结果 result_2.txt-------------------------
北京大学: 林衡 st018[总分:375, 英语: 93, 化学: 95, 代数: 96, 计算机: 91]
北京大学: 胡量 st019[总分:374, 英语: 98, 化学: 94, 代数: 93, 计算机: 89]
清华大学: 郑来 st017[总分:363, 英语: 89, 化学: 88, 代数: 90, 计算机: 96]
北京大学: 李方 st010[总分:344, 英语: 77, 化学: 86, 代数: 99, 计算机: 82]
北京大学:[达标] 当前录取3/总名额3
清华大学: 邹代 st020[总分:344, 英语: 87, 化学: 96, 代数: 79, 计算机: 82]
清华大学: 杨四 st004[总分:342, 英语: 78, 化学: 85, 代数: 83, 计算机: 96]
清华大学:[达标] 当前录取3/总名额3
复旦大学: 赵五 st005[总分:342, 英语: 79, 化学: 87, 代数: 91, 计算机: 85]
复旦大学: 赵度 st016[总分:342, 英语: 67, 化学: 98, 代数: 78, 计算机: 99]
复旦大学: 张一 st001[总分:340, 英语: 80, 化学: 90, 代数: 70, 计算机:100]
复旦大学: 李码 st021[总分:339, 英语: 77, 化学: 87, 代数: 89, 计算机: 86]
南京大学: 李二 st002[总分:320, 英语: 77, 化学: 88, 代数: 99, 计算机: 56]
复旦大学: 郑陆 st006[总分:320, 英语: 79, 化学: 87, 代数: 68, 计算机: 86]
南京大学:[未达标] 当前录取1/总名额10
复旦大学:[未达标] 当前录取5/总名额10
南京职业技术学院: 宁的 st022[总分:318, 英语: 94, 化学: 76, 代数: 69, 计算机: 79]
南京职业技术学院: 李度 st013[总分:310, 英语: 67, 化学: 87, 代数: 78, 计算机: 78]
南京职业技术学院: 王三 st003[总分:309, 英语: 96, 化学: 56, 代数: 88, 计算机: 69]
南京职业技术学院: 胡长 st008[总分:299, 英语: 69, 化学: 86, 代数: 75, 计算机: 69]
南京职业技术学院: 张杂 st012[总分:298, 英语: 44, 化学: 66, 代数: 99, 计算机: 89]
南京职业技术学院: 邹家 st009[总分:292, 英语: 84, 化学: 69, 代数: 90, 计算机: 49]
南京职业技术学院: 林世 st007[总分:291, 英语: 55, 化学: 78, 代数: 90, 计算机: 68]
南京职业技术学院: 宁可 st011[总分:279, 英语: 67, 化学: 87, 代数: 69, 计算机: 56]
南京职业技术学院:[达标] 当前录取8/总名额(无限制)
未被录取:张质 st023[总分:240, 英语: 87, 化学: 57, 代数: 48, 计算机: 48]
未被录取:王等 st014[总分:233, 英语: 56, 化学: 78, 代数: 88, 计算机: 11]
未被录取:杨角 st015[总分:209, 英语: 0, 化学: 44, 代数: 66, 计算机: 99]