簡體   English   中英

Java中的同步數據庫訪問

[英]Synchronized DB Access in Java

我有一個數據庫,其中包含要發送的電子郵件。 我正在使用多個線程來發送這些電子郵件。 我使用的方法是每個線程將查詢數據庫,在內存中獲取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
  }
}

您需要一種方法來共享一個方法//以控制並發。 整理語句以獲取電子郵件並標記它們。 然后發送電子郵件。 像這樣:

public void processMails(){
     List<String> mails;
     synchronized(this){
           mails  = getMails();
           markMails(mails);
      }
      sendMails(mails);

  }

此方法可以在您的DAO Facade中,所有線程都可以訪問。

編輯:

如果您有DAO類的多個實例:

public void processMails(){
         List<String> mails;
         synchronize(DAO.class){
               mails  = getMails();
               markMails(mails);
          }
          sendMails(mails);

      }

其他選擇

private static final Object LOCK = new Object();

   public void processMails(){
             List<String> mails;
             synchronize(LOCK){
                   mails  = getMails();
                   markMails(mails);
              }
              sendMails(mails);

          }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM