我有一个数据库,其中包含要发送的电子邮件。我使用多个线程来发送这些电子邮件。我使用的方法是每个线程都会查询数据库,在内存中获取 N 封电子邮件并将其标记为已发送。另一个线程将看到这 N 封电子邮件已标记,并继续获取下 N 个条目。
现在这不起作用,因为线程 1 可以更新正在发送的条目,线程 2 查询电子邮件,因此两个线程最终都会收到同一组电子邮件。
每个线程都有自己的数据库连接。这是这种行为的根本原因吗?我应该在所有线程之间共享一个连接对象吗? 或者我可以使用更好的方法吗?
最佳答案
我的建议是让一个线程负责查询数据库,将检索到的电子邮件放入线程安全队列中(例如 ArrayBlockingQueue ,其优点是有界);然后,您可以使用任意数量的线程从该队列中删除和处理电子邮件。 ArrayBlockingQueue
上的同步开销相当轻,这样您就不需要使用数据库事务或类似的东西。
class EmailChunk {
Email[] emails;
}
// only instantiate one of these
class DatabaseThread implements Runnable {
final BlockingQueue<EmailChunk> emailQueue;
public DatabaseThread(BlockingQueue<EmailChunk> emailQueue) {
this.emailQueue = emailQueue;
}
public void run() {
EmailChunk newChunk = // query database, create email chunk
// add newChunk to queue, wait 30 seconds if it's full
emailQueue.offer(newChunk, 30, TimeUnit.SECONDS);
}
}
// instantiate as many of these as makes sense
class EmailThread implements Runnable {
final BlockingQueue<EmailChunk> emailQueue;
public EmailThread(BlockingQueue<EmailChunk> emailQueue) {
this.emailQueue = emailQueue;
}
public void run() {
// take next chunk from queue, wait 30 seconds if queue is empty
emailChunk nextChunk = emailQueue.poll(30, TimeUnit.SECONDS);
}
}
class Main {
final int queueSize = 5;
public static void main(String[] args) {
BlockingQueue<EmailChunk> emailQueue = new ArrayBlockingQueue<>(queueSize);
// instantiate DatabaseThread and EmailThread objects with this queue
}
}
关于java - Java 中的同步数据库访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30246578/