java并发和排序的简单例子(Runnable+TreeSet)
很多时候并发需要考虑线程安全,但也有很多时候和线程安全毛关系都没有,因为并发最大的作用是并行,线程安全仅仅是并发的一个子话题。
例如常常会用于并发运算,并发i/o。
下文是一个练习笔记。
运行环境:windows 11,jdk17
1.Pojo--StudentExamScoreSummary
package study.model.school; import java.math.BigDecimal; import java.util.Date; public class StudentExamScoreSummary implements Comparable<StudentExamScoreSummary>{ private Integer id; private Integer studentId; private Integer theYear; private BigDecimal lanScore; private BigDecimal mathScore; private BigDecimal physicalScore; private BigDecimal politicsScore; private BigDecimal philosophyScore; private BigDecimal avgScore; private Date optime; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getStudentId() { return studentId; } public void setStudentId(Integer studentId) { this.studentId = studentId; } public Integer getTheYear() { return theYear; } public void setTheYear(Integer theYear) { this.theYear = theYear; } public BigDecimal getLanScore() { return lanScore; } public void setLanScore(BigDecimal lanScore) { this.lanScore = lanScore; } public BigDecimal getMathScore() { return mathScore; } public void setMathScore(BigDecimal mathScore) { this.mathScore = mathScore; } public BigDecimal getPhysicalScore() { return physicalScore; } public void setPhysicalScore(BigDecimal physicalScore) { this.physicalScore = physicalScore; } public BigDecimal getPoliticsScore() { return politicsScore; } public void setPoliticsScore(BigDecimal politicsScore) { this.politicsScore = politicsScore; } public BigDecimal getPhilosophyScore() { return philosophyScore; } public void setPhilosophyScore(BigDecimal philosophyScore) { this.philosophyScore = philosophyScore; } public BigDecimal getAvgScore() { return avgScore; } public void setAvgScore(BigDecimal avgScore) { this.avgScore = avgScore; } public Date getOptime() { return optime; } public void setOptime(Date optime) { this.optime = optime; } public BigDecimal calAvgScore() { return (this.lanScore.add(this.mathScore).add(this.physicalScore).add(this.politicsScore) .add(this.philosophyScore)).divide(new BigDecimal(5)); } @Override public int compareTo(StudentExamScoreSummary o) { return this.avgScore.compareTo(o.getAvgScore()); } }
2.线程和测试代码-ConcurrentListRunable
/** * */ package study.base.types.collection.list; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeSet; import study.model.school.StudentExamScoreSummary; /** * @author luzhifei * */ public class ConcurrentListRunable implements Runnable { private List<StudentExamScoreSummary> scoreList; private Map<String, Boolean> flag; public ConcurrentListRunable(List<StudentExamScoreSummary> list, Map<String, Boolean> flag) { this.scoreList = list; this.flag = flag; } @Override public void run() { int len = scoreList.size(); String courseName = Thread.currentThread().getName(); for (int i = 0; i < len; i++) { StudentExamScoreSummary item = scoreList.get(i); double rscore = Math.random() * 100; BigDecimal dScore = new BigDecimal(rscore); dScore.setScale(1, RoundingMode.HALF_UP); synchronized (scoreList) { switch (courseName) { case "语文": item.setLanScore(dScore); break; case "数学": item.setMathScore(dScore); break; case "物理": item.setPhysicalScore(dScore); break; case "政治": item.setPoliticsScore(dScore); break; case "哲学": item.setPhilosophyScore(dScore); break; } } try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } flag.put(courseName, true); } public static void main(String[] args) { int tty = 10; String[] courses = new String[] { "数学", "语文", "物理", "政治", "哲学" }; Map<String, Boolean> flag = new HashMap<String, Boolean>(5); for (int i = 0; i < courses.length; i++) { flag.put(courses[i], false); } List<StudentExamScoreSummary> sList = new ArrayList<StudentExamScoreSummary>(); for (int i = 0; i < tty; i++) { StudentExamScoreSummary score = new StudentExamScoreSummary(); score.setId(i); score.setStudentId(i); score.setTheYear(2024); sList.add(score); } List<StudentExamScoreSummary> conList = Collections.synchronizedList(sList); ConcurrentListRunable job = new ConcurrentListRunable(conList, flag); List<Thread> jobs = new ArrayList<>(); for (int i = 0; i < courses.length; i++) { Thread t = new Thread(job, courses[i]); jobs.add(t); } for (int i = 0; i < courses.length; i++) { jobs.get(i).start(); } boolean isDone = false; while (isDone == false) { isDone = true; for (int i = 0; i < courses.length; i++) { if (flag.get(courses[i]) == false) { isDone = false; break; } } } DecimalFormat df = new DecimalFormat("#00.0"); for (int i = 0; i < sList.size(); i++) { StudentExamScoreSummary item = sList.get(i); BigDecimal avgScore = item.calAvgScore(); item.setAvgScore(avgScore); String scoreTxt = item.getStudentId().toString() + "-【语文】" + df.format(item.getLanScore()) + " 【数学】" + df.format(item.getMathScore()) + " 【物理】" + df.format(item.getPhysicalScore()) + " 【政治】" + df.format(item.getPoliticsScore()) + " 【哲学】" + df.format(item.getPhilosophyScore()) + " |平均成绩:" + df.format(avgScore); System.out.println(scoreTxt); } // 排序 System.out.println("排序------------------------------------------"); TreeSet<StudentExamScoreSummary> ts = new TreeSet<StudentExamScoreSummary>(sList); for (Iterator<StudentExamScoreSummary> iter = ts.iterator(); iter.hasNext();) { StudentExamScoreSummary item = iter.next(); System.out.println(item.getStudentId().toString() + " 平均成绩:" + df.format(item.getAvgScore())); } } }
测试结果1:
0-【语文】94.6 【数学】67.6 【物理】38.0 【政治】47.2 【哲学】35.3 |平均成绩:56.5
1-【语文】23.2 【数学】89.8 【物理】70.7 【政治】68.9 【哲学】49.3 |平均成绩:60.4
2-【语文】36.6 【数学】19.1 【物理】21.8 【政治】36.4 【哲学】75.6 |平均成绩:37.9
3-【语文】89.6 【数学】14.4 【物理】44.4 【政治】80.6 【哲学】07.1 |平均成绩:47.2
4-【语文】82.0 【数学】18.2 【物理】70.2 【政治】63.9 【哲学】17.4 |平均成绩:50.4
5-【语文】27.4 【数学】04.2 【物理】37.7 【政治】17.8 【哲学】20.1 |平均成绩:21.5
6-【语文】10.5 【数学】64.8 【物理】68.7 【政治】21.0 【哲学】97.2 |平均成绩:52.4
7-【语文】12.4 【数学】98.9 【物理】95.8 【政治】03.7 【哲学】56.3 |平均成绩:53.4
8-【语文】40.3 【数学】48.7 【物理】53.7 【政治】61.4 【哲学】42.9 |平均成绩:49.4
9-【语文】70.1 【数学】39.3 【物理】41.6 【政治】77.6 【哲学】87.3 |平均成绩:63.2
排序------------------------------------------
5 平均成绩:21.5
2 平均成绩:37.9
3 平均成绩:47.2
8 平均成绩:49.4
4 平均成绩:50.4
6 平均成绩:52.4
7 平均成绩:53.4
0 平均成绩:56.5
1 平均成绩:60.4
9 平均成绩:63.2
注意事项:
1.StudentExamScoreSummary必须实现Comparable接口,因为测试代码使用TreeSet
TreeSet<StudentExamScoreSummary> ts = new TreeSet<StudentExamScoreSummary>(sList);
以上代码调用的构造函数是:
public TreeSet(Collection<? extends E> c) {
this();
addAll(c);
}
这个构造函数要求入参必须实现Comparable接口(如果参数不是简单的java类型)。
2.Collections.synchronizedList的结果要求手动调用sychronized
否则可能会线程不安全。
3.代码仅仅是为了演示使用5个线程各自生成成绩,不考虑效率问题。高效且正确的做法应该是分别计算5个不相干的List。
我们需要使用并发list的时候,正常情况下,多数是因为以下理由:
- 对list的操作仅仅占据了很少的计算资源,线程更多的时候是做其它更耗费资源的事情
- 为了实现异步操作