Environment: Windows 11, JDK 17
1. POJO – ExamScoreRecord
import java.math.BigDecimal; import java.util.Date;
public class ExamScoreRecord implements Comparable<ExamScoreRecord> { private Integer id; private Integer studentId; private Integer academicYear; private BigDecimal languageScore; private BigDecimal mathScore; private BigDecimal physicsScore; private BigDecimal politicsScore; private BigDecimal philosophyScore; private BigDecimal averageScore; private Date updatedTime;
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 getAcademicYear() {
return academicYear;
}
public void setAcademicYear(Integer academicYear) {
this.academicYear = academicYear;
}
public BigDecimal getLanguageScore() {
return languageScore;
}
public void setLanguageScore(BigDecimal languageScore) {
this.languageScore = languageScore;
}
public BigDecimal getMathScore() {
return mathScore;
}
public void setMathScore(BigDecimal mathScore) {
this.mathScore = mathScore;
}
public BigDecimal getPhysicsScore() {
return physicsScore;
}
public void setPhysicsScore(BigDecimal physicsScore) {
this.physicsScore = physicsScore;
}
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 getAverageScore() {
return averageScore;
}
public void setAverageScore(BigDecimal averageScore) {
this.averageScore = averageScore;
}
public Date getUpdatedTime() {
return updatedTime;
}
public void setUpdatedTime(Date updatedTime) {
this.updatedTime = updatedTime;
}
public BigDecimal calculateAverage() {
BigDecimal total = this.languageScore.add(this.mathScore)
.add(this.physicsScore)
.add(this.politicsScore)
.add(this.philosophyScore);
return total.divide(new BigDecimal(5), 2, BigDecimal.ROUND_HALF_UP);
}
@Override
public int compareTo(ExamScoreRecord other) {
return this.averageScore.compareTo(other.getAverageScore());
}
}
</div>**2. Runnable and Test Code – `ScorePopulator`**
<div>```
package study.base.types.collection.list;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.*;
import study.model.school.ExamScoreRecord;
public class ScorePopulator implements Runnable {
private final List<ExamScoreRecord> records;
private final Map<String, Boolean> completionFlags;
public ScorePopulator(List<ExamScoreRecord> records, Map<String, Boolean> flags) {
this.records = records;
this.completionFlags = flags;
}
@Override
public void run() {
int size = records.size();
String subject = Thread.currentThread().getName();
for (int i = 0; i < size; i++) {
ExamScoreRecord record = records.get(i);
BigDecimal randomScore = new BigDecimal(Math.random() * 100)
.setScale(1, RoundingMode.HALF_UP);
synchronized (records) {
switch (subject) {
case "Language" -> record.setLanguageScore(randomScore);
case "Math" -> record.setMathScore(randomScore);
case "Physics" -> record.setPhysicsScore(randomScore);
case "Politics" -> record.setPoliticsScore(randomScore);
case "Philosophy" -> record.setPhilosophyScore(randomScore);
}
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
completionFlags.put(subject, true);
}
public static void main(String[] args) {
int studentCount = 10;
String[] subjects = {"Math", "Language", "Physics", "Politics", "Philosophy"};
Map<String, Boolean> flags = new HashMap<>(subjects.length);
for (String s : subjects) {
flags.put(s, false);
}
List<ExamScoreRecord> recordList = new ArrayList<>();
for (int i = 0; i < studentCount; i++) {
ExamScoreRecord rec = new ExamScoreRecord();
rec.setId(i);
rec.setStudentId(i);
rec.setAcademicYear(2024);
recordList.add(rec);
}
List<ExamScoreRecord> syncedRecords = Collections.synchronizedList(recordList);
ScorePopulator job = new ScorePopulator(syncedRecords, flags);
List<Thread> threads = new ArrayList<>();
for (String subject : subjects) {
threads.add(new Thread(job, subject));
}
threads.forEach(Thread::start);
// Wait until all threads complete
boolean allFinished = false;
while (!allFinished) {
allFinished = true;
for (String s : subjects) {
if (Boolean.FALSE.equals(flags.get(s))) {
allFinished = false;
break;
}
}
}
DecimalFormat df = new DecimalFormat("#00.0");
for (ExamScoreRecord r : recordList) {
BigDecimal avg = r.calculateAverage();
r.setAverageScore(avg);
String output = r.getStudentId() + "-【Language】" + df.format(r.getLanguageScore()) +
" 【Math】" + df.format(r.getMathScore()) +
" 【Physics】" + df.format(r.getPhysicsScore()) +
" 【Politics】" + df.format(r.getPoliticsScore()) +
" 【Philosophy】" + df.format(r.getPhilosophyScore()) +
" | Average: " + df.format(avg);
System.out.println(output);
}
// Sort using TreeSet
System.out.println("Sorted------------------------------------------");
TreeSet<ExamScoreRecord> sortedSet = new TreeSet<>(recordList);
for (ExamScoreRecord r : sortedSet) {
System.out.println(r.getStudentId() + " Average: " + df.format(r.getAverageScore()));
}
}
}
1. ExamScoreRecord must implement Comparable because TreeSet relies on natural ordering when constructed from a collection:
TreeSet<ExamScoreRecord> ts = new TreeSet<>(recordList);
// Calls: public TreeSet(Collection<? extends E> c) { this(); addAll(c); }
// This constructor requires the elements to implement Comparable (unless a custom Comparator is provided).
2. Collections.synchronizedList still requires explicit synchronization
Eventhough the list is wrapped with synchronizedList, compound operations such as setting a score must be synchronized manually to avoid thread interference.
3. The example purely illustrates parallel score generation with five threads; it is not optimized for performance. A more efficient approach would operate on independent lists per subject and merge results later.
Concurrent lists are typically used when:
- List manipulation represents a small fraction of the overall work, and threads perform more resource-intensive tasks.
- Asynchronous processing is required.