java一次只运行一个实例

java一次只运行一个实例,java,multithreading,jakarta-mail,Java,Multithreading,Jakarta Mail,我正在使用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 } } Ema

我正在使用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,它从数据库接收要发送的电子邮件并形成它们,然后将这些参数传递给
EmailSender
类的
SendEmail()

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

如有任何建议,将不胜感激

更新1 我无法在用户单击按钮后禁用它。因为如果用户刷新页面,则默认情况下将启用该按钮

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

您可以使用队列数据结构将发送电子邮件请求排队,并在单独的线程中处理相同的请求。此线程将在启动期间生成一次,并将处理队列。发送电子邮件时,将清除
状态='NOTSENT'
,这将解决多个电子邮件问题。队列可以按固定的时间间隔进行处理,也可以轮询数据,或者使用某种信号发送机制在队列中有数据时向线程发送信号


编辑:我认为此解决方案适合更新1更新2

您可以使用队列数据结构将发送电子邮件请求排队,并在单独的线程中处理。此线程将在启动期间生成一次,并将处理队列。发送电子邮件时,将清除
状态='NOTSENT'
,这将解决多个电子邮件问题。队列可以按固定的时间间隔进行处理,也可以轮询数据,或者使用某种信号发送机制在队列中有数据时向线程发送信号


编辑:我认为此解决方案适合更新1更新2我会在InvokeSender中使用原子布尔值,然后执行以下操作:

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); 
    }
  }
}

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

我将在InvokeSender中使用原子布尔,然后执行以下操作:

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); 
    }
  }
}

当然,这是一个非常简单的解决方案,如果你想要更复杂的行为,比如限制上一封邮件和下一封邮件之间的时间,你就必须增加一些逻辑性。

我认为,可以通过为页面创建一个会话范围为的唯一令牌来完成,该页面在Servlet类中具有电子邮件发送者和单例映射,以维护令牌

  • 创建一个servlet过滤器,为页面生成会话范围内的令牌

  • 如果标记在映射中不存在,则将该标记添加到 映射并调用邮件发送者

  • 如果包含,则不要调用邮件 寄件人


  • 我认为,可以通过为页面创建一个唯一的令牌,该令牌的会话范围为email sender和Servlet类中的单例映射来维护令牌

  • 创建一个servlet过滤器,为页面生成会话范围内的令牌

  • 如果标记在映射中不存在,则将该标记添加到 映射并调用邮件发送者

  • 如果包含,则不要调用邮件 寄件人


  • 使用同步化块

            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);
              }
            }
    

    使用同步化块

            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);
              }
            }
    

    在用户单击按钮后简单地禁用按钮怎么样?禁用按钮是一个好主意,但是我认为其目的是构建一个对UI没有依赖性的健壮的服务器组件。例如,您可能希望通过web服务接口公开此功能。@Joe请参阅
    update1
    如何进行ajax调用(发送针对用户发送的电子邮件并将电子邮件存储在表中),并禁用该按钮。在页面加载时,检查是否未发送电子邮件,如果用户已发送邮件,则启用按钮?@Bhushan,直到您希望在多长时间内不向他发送下一封邮件。实现将取决于此。在用户单击按钮后简单地禁用按钮如何?禁用按钮是一个好主意,但是我认为其目的是构建一个对UI没有依赖性的健壮服务器组件。例如,您可能希望通过web服务界面公开此功能。@Joe请参阅
    update1
    如何进行ajax调用(发送电子邮件并将针对用户发送的电子邮件存储在表中)并禁用该按钮。在页面加载时,检查是否未发送电子邮件,如果用户已发送邮件,则启用按钮?@Bhushan,直到您希望在多长时间内不向他发送下一封邮件。实施将取决于这一点。