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的操作仅仅占据了很少的计算资源,线程更多的时候是做其它更耗费资源的事情
  • 为了实现异步操作

 

posted @ 2022-05-30 20:21  正在战斗中  阅读(91)  评论(0编辑  收藏  举报