Java多线程分数增减作业求助:实现线程安全的Runnable方案
Hey there! Let's get your thread-safe score updater working properly. Your core goal is clear: two Score objects, 20 total threads (5 increment + 5 decrement per score), all using Runnable and thread-safe operations. Let's break down what's missing in your current code, then walk through the corrected version.
What's Off in Your Current Implementation
- Your
ScoreRunnerDemodoesn't connect to anyScoreinstance — it has its own score field which isn't what you need. Each thread should operate on one of the two sharedScoreobjects. - There's no logic for incrementing or decrementing the score; the
run()method just prints a counter. - The
mainmethod has invalid code (likeScoreRunnerDemo.getScorewhich doesn't exist, andScoreRunner()which isn't a valid call) and doesn't properly create/start threads. - You haven't differentiated between increment and decrement threads — each thread needs to know whether to add or subtract from the score.
Corrected Code
First, your Score class is actually already thread-safe thanks to the synchronized modifier on updateScore — we don't need to change that. Let's fix the rest:
Runnable Class (ScoreUpdater)
This class will handle modifying a specific Score instance with a given change amount (positive for increment, negative for decrement):
class ScoreUpdater implements Runnable { private final Score targetScore; private final double changeAmount; // Constructor to pass in the Score to modify and the change value public ScoreUpdater(Score targetScore, double changeAmount) { this.targetScore = targetScore; this.changeAmount = changeAmount; } @Override public void run() { try { // Each thread performs 5 updates (matches your original loop intent) for (int i = 0; i < 5; i++) { targetScore.updateScore(changeAmount); Thread.sleep(100); // Simulate work between updates } } catch (InterruptedException e) { System.out.printf("Thread updating Score ID %d was interrupted%n", targetScore.getId()); Thread.currentThread().interrupt(); // Preserve interrupt status for cleanup } System.out.printf("Finished updating Score ID %d with change %.2f%n", targetScore.getId(), changeAmount); } }
Main Class (ScoreRunner)
This creates the two Score objects, sets up all 20 threads, starts them, and waits for completion:
public class ScoreRunner { public static void main(String[] args) { // Create two Score objects with unique IDs and initial score 100 Score score1 = new Score(1, 100.0); Score score2 = new Score(2, 100.0); // Array to hold all 20 threads for easy management Thread[] threads = new Thread[20]; int threadIndex = 0; // 5 increment threads for Score 1 (+1.0 per update) for (int i = 0; i < 5; i++) { threads[threadIndex++] = new Thread(new ScoreUpdater(score1, 1.0), "Score1-Inc-" + (i+1)); } // 5 decrement threads for Score 1 (-1.0 per update) for (int i = 0; i < 5; i++) { threads[threadIndex++] = new Thread(new ScoreUpdater(score1, -1.0), "Score1-Dec-" + (i+1)); } // 5 increment threads for Score 2 (+1.0 per update) for (int i = 0; i < 5; i++) { threads[threadIndex++] = new Thread(new ScoreUpdater(score2, 1.0), "Score2-Inc-" + (i+1)); } // 5 decrement threads for Score 2 (-1.0 per update) for (int i = 0; i < 5; i++) { threads[threadIndex++] = new Thread(new ScoreUpdater(score2, -1.0), "Score2-Dec-" + (i+1)); } // Start all threads for (Thread t : threads) { t.start(); } // Wait for all threads to finish before printing final scores (good practice) try { for (Thread t : threads) { t.join(); } } catch (InterruptedException e) { System.out.println("Main thread interrupted while waiting for worker threads"); } // Print final state of both Score objects System.out.println("\nFinal Scores:"); System.out.println("Score ID " + score1.getId() + ": " + score1.getScore()); System.out.println("Score ID " + score2.getId() + ": " + score2.getScore()); } }
Key Explanations
- Thread Safety: Your
Score.updateScoremethod usessynchronized, which ensures only one thread can execute that method at a time for a givenScoreinstance. This eliminates race conditions where multiple threads try to modify the score simultaneously. - Flexible Runnable:
ScoreUpdateris designed to work with anyScoreand any change amount — you could easily adjust the number of updates or the change value without rewriting the whole class. - Thread Management: Using an array to hold threads makes it easy to start and join all of them. Calling
join()ensures the main thread waits for all worker threads to finish before printing the final scores, so you get accurate results. - Debugging: We named each thread (e.g., "Score1-Inc-3") to make it easier to track which thread is doing what if you need to debug.
内容的提问来源于stack exchange,提问作者Jay

