并发访问时树图中的重复键

时间:2016-12-07 15:07:12

标签: java multithreading concurrency treemap sortedmap

有人可以在此代码中找到并发错误吗?代码对于一个线程工作得非常好,但是我很快就会在同一时间启动2个线程并调用addScore方法,它会在树Map中添加重复项。

与被覆盖的被覆盖的pojo如下:

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 个答案:

答案 0 :(得分:3)

你的比较搞砸了。您可以使用类似这样的单线程获得相同的结果

    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)并且由于用户不匹配,因此不比较它们并比较这些值。如果它已经比较了用户标识,那么它就会向左移,但是它向右移动并且仅将项目与一个用户标识进行比较

您可以始终比较这两个值,或始终只比较userId,但您无法来回切换。

@Override
public int compareTo(UserHighScore uh) {
    return Integer.compare(userId, uh.userId);
}