插入时应为每个线程分配唯一的ID

时间:2013-02-06 01:28:42

标签: java multithreading blockingqueue

我需要插入有两列的数据库 -

ID Primary Key String
Data String

这意味着ID每次都应该是唯一的,否则在插入时会抛出duplicate row in unique index异常。我需要在此范围1-100000

之间选择ID

这意味着每个线程应始终使用唯一ID -

下面是我编写的多线程程序,每次从ArrayBlockingQueue获取后将插入到具有不同唯一ID的数据库中。

那么这个程序是否可以是线程安全的?或者还有其他更好的方法来获取每个线程的唯一ID吗?或者以下程序可能导致duplicate row in unique index

private static LinkedList<Integer> availableExistingIds = new LinkedList<Integer>();

public static void main(String[] args) {

        for (int i = 1; i <= 100000; i++) {
            availableExistingIds.add(i);
        }

        BlockingQueue<Integer> pool = new ArrayBlockingQueue<Integer>(200000, false, availableExistingIds);

        ExecutorService service = Executors.newFixedThreadPool(10);

            for (int i = 0; i < noOfTasks * noOfThreads; i++) {
                service.submit(new ThreadTask(pool));
            }
}   

class ThreadTask implements Runnable {

    private BlockingQueue<Integer> pool;
    private int id;

    public ThreadTask(BlockingQueue<Integer> pool) {
        this.pool = pool;
    }

    @Override
    public void run() {

         try {
            dbConnection = getDBConnection();
            preparedStatement = dbConnection.prepareStatement(INSERT_SQL);

            id = pool.take();

            preparedStatement.setString(1, String.valueOf(id));
            preparedStatement.setString(2, ACCOUNT);

            preparedStatement.executeUpdate();

       } finally {
         pool.offer(id);
        }

    }
}   

2 个答案:

答案 0 :(得分:2)

pool.offer(id)表示您将已使用的ID放回队列中 - 因此可以在以后由另一个线程重用。这可能是一个问题(因为队列是FIFO,你将在100,001次插入时获得重复的ID)。

在任何情况下,静态AtomicInteger在不使用队列的情况下执行相同操作时似乎非常复杂:

class ThreadTask implements Runnable {

    private final AtomicInteger id;

    ThreadTask(AtomicInteger id) {
        this.id = id; //in your main thread: id = new AtomicInteger(minId);
    }

    @Override
    public void run() {
        dbConnection = getDBConnection();
        preparedStatement = dbConnection.prepareStatement(INSERT_SQL);

        preparedStatement.setString(1, String.valueOf(id.getAndIncrement()));
        preparedStatement.setString(2, ACCOUNT);

        preparedStatement.executeUpdate();
    }
}

注意:评论时,您的数据库可能会为您分配唯一的ID。

答案 1 :(得分:1)

identity列是数据库为每个插入分配新唯一值的列。见here

我不知道这个XpressMP数据库,但您应该在文档中搜索identityauto-increment类型。您也可以稍微花费guid类型使用IdProvider类型。

请记住,当程序重新启动时,您必须在最后分配的ID之后开始。但是你仍然不需要一个队列,只需要一个带有同步nextId方法的{{1}}类,该方法递增并返回一个已经初始化为最后一个分配id的私有变量。