java一次只运行一个实例

时间:2013-11-06 04:58:00

标签: java multithreading javamail

我使用Java(Servlet,JSP)开发Web应用程序。

我有一个发送电子邮件的课程。

类看起来像:

public class EmailSender
{
    String SendEmail(String from,Session session,String To,String CC, String BCC, String Subject,String Body)
    {
        //Actual code for sending emails
    }
}
从另一个类调用

EmailSender类:

public class InvokeSender
{
    public InvokeSender(String dbFileName)
    {
        //get emails from database for sending who has STATUS='NOTSENT'
        //statements to get all required parameter to pass to SendEmail()
        EmailSender sender = new EmailSender();
        String msg = sender.SendEmail(fromEmail,session,To,CC,BCC,SUBJECT,BODY);
    }
}

当用户点击按钮时,将从servlet调用InvokeSender

当用户点击按钮时,会调用InvokeSender,它会从数据库发送电子邮件并形成它们,然后将这些参数传递给SendEmail()类的EmailSender

我希望一次只运行一个InvokeSender个实例,以避免在按两次按钮时同一封电子邮件发送两次。如何处理?在这种情况下,multithreading会有用吗?

任何建议都将受到赞赏。

UPDATE1 用户点击后我无法禁用该按钮。因为如果用户刷新页面,那么默认情况下将启用该按钮。

UPDATE2 第一个用户选择客户,模板等发送电子邮件,然后将电子邮件参数存储在数据库中。 InvokeSender课程会收到要发送的所有电子邮件。无法预测要发送的电子邮件数。它可以是1或500或更多。我只希望运行InvokeSender的一个实例,直到上一个实例完成发送电子邮件。功能(生成和发送电子邮件的按钮)将向5-7个用户公开。

4 个答案:

答案 0 :(得分:2)

我认为,可以通过创建一个具有会话范围的唯一令牌来完成,该页面具有电子邮件发件人和Servlet类中的Singleton Map以维护令牌。

  1. 创建servlet过滤器以生成页面的会话范围标记。

  2. 如果地图中不存在令牌,则将令牌添加到     映射并调用邮件发件人。

  3. 如果包含,则不要调用邮件     发送方

答案 1 :(得分:1)

您可以使用队列数据结构对发送电子邮件请求进行排队,并在单独的线程中处理它们。该线程将在启动期间生成一次并将处理队列。发送电子邮件后,STATUS='NOTSENT'将被清除,这将解决多个电子邮件问题。队列可以定期处理,也可以轮询数据,或者有一些信号机制在队列中有数据时发出信号。

修改:我认为此解决方案适合 Update1 Update2

答案 2 :(得分:1)

我会在InvokeSender中使用AtomicBoolean然后执行此操作:

public class InvokeSender
{
  static AtomicBoolean sendInProgress = new AtomicBoolean(false);

  public InvokeSender(String dbFileName)
  {
    if (sendInProgress.compareAndSet(false, true)) {

      //get emails from database for sending who has STATUS='NOTSENT'
      //statements to get all required parameter to pass to SendEmail()
      EmailSender sender = new EmailSender();
      String msg = sender.SendEmail(fromEmail,session,To,CC,BCC,SUBJECT,BODY);

      sendInProgress.set(false); 
    }
  }
}

当然,这是一个非常简单的解决方案,如果您想要更复杂的行为,例如限制上一封电子邮件和下一封电子邮件之间的时间,您将不得不为此添加更多逻辑。

答案 3 :(得分:1)

使用synchronized块

        public InvokeSender(String dbFileName)
        {
           synchronized(InvokeSender.class){ 
           //get emails from database for sending who has STATUS='NOTSENT'
            //statements to get all required parameter to pass to SendEmail()
            EmailSender sender = new EmailSender();
            String msg = sender.SendEmail(fromEmail,session,To,CC,BCC,SUBJECT,BODY);
          }
        }