Дублированные ключи в древовидной карте при одновременном доступе
Может ли кто-нибудь найти ошибку параллелизма в этом коде? Код прекрасно работает для одного потока, но как только я запускаю 2 потока одновременно и вызываю метод addScore, он добавляет дубликаты в древовидную карту.
Пойо с переопределенным сравнению является следующим:
public final class UserHighScore implements Comparable<UserHighScore>{
private final int userId;
private final int value;
public UserHighScore(int userId, int value) {
this.userId = userId;
this.value = value;
}
public int getUserId() {
return userId;
}
public int getValue() {
return value;
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (!(obj instanceof UserHighScore)) {
return false;
}
UserHighScore userHighScore = (UserHighScore) obj;
return userHighScore.userId==userId;
}
@Override
public int compareTo(UserHighScore uh) {
if(uh.getUserId()==this.getUserId()) return 0;
if(uh.getValue()>this.getValue()) return 1;
return -1;
}
}
Это код, который я использую для имитации запросов пользователя:
class User implements Runnable
{
private ScoreServiceImpl scoreService=ScoreServiceImpl.getInstance();
CountDownLatch latch;
public User(CountDownLatch latch)
{
this.latch = latch;
}
@Override
public void run() {
for(int i=0;i<5;i++) {
scoreService.addScore(3,Integer.parseInt(Thread.currentThread().getName()),ThreadLocalRandom.current().nextInt(50000));
}
System.out.println(scoreService.getHighScoreList(3));
}
}
И основной метод создания потоков:
public static void main(String[] args) throws InterruptedException {
SpringApplication.run(RestclientApplication.class, args);
CountDownLatch latch = new CountDownLatch(1);
User user1=new User(latch);
User user2=new User(latch);
Thread t1=new Thread(user1);
Thread t2=new Thread(user2);
t1.setName("1");
t2.setName("2");
t1.start();
t2.start();
//latch.countDown();
}
1 ответ
Ваше сравнение с вином. Вы можете получить тот же результат однопоточным с чем-то вроде этого
ScoreServiceImpl.getInstance().addScore(0,1,4);
ScoreServiceImpl.getInstance().addScore(0,1,12);
ScoreServiceImpl.getInstance().addScore(0,0,10);
ScoreServiceImpl.getInstance().addScore(0,0,3);
Дерево устанавливает работу по принципу разделяй и властвуй, сначала проверяет парня посередине. (это будет 1, 4), и поскольку userIds не совпадают, он не сравнивает их, а сравнивает значения. если бы он сравнил идентификаторы пользователей, он пошел бы налево, но вместо этого он пошел направо и сравнил только элементы с идентификатором пользователя, равным единице.
Вы можете всегда сравнивать оба значения или всегда сравнивать только по идентификатору пользователя, но вы не можете переключаться между ними.
@Override
public int compareTo(UserHighScore uh) {
return Integer.compare(userId, uh.userId);
}