Executar uma thread a cada 1 minuto

Oi pessoal;

Desenvolvi um sisteminha para a empresa em que trabalho e preciso implementar uma rotina que procura uma determinada sequencia de informações no banco de dados e envia um e-mail para determinados usuários.
A parte do envio de e-mail está funcionando perfeitamente.
O que eu ainda não consegui fazer é que esta rotina seja executada a cada 1 minuto (apenas como exemplo).

Esta rotina é executada assim que o programa é executado e fica rodando até que o programa seja fechado.

Já tente de várias formas e não deu certo.
Será que alguém pode me ajudar ?

Código da Thread.

class MontaEmail extends Thread
{
    String usuario;

    public MontaEmail(String vusuario)
    {
        this.usuario = vusuario;
    }

    public void run()
    {
        Conexao cnx = new Conexao();
        cnx.conecta();

        SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
        SimpleDateFormat format1 = new SimpleDateFormat("yyyy/MM/dd");
        Date data = new Date();

        try
        {
            PreparedStatement stms = cnx.conexao.prepareStatement(
                "SELECT A.ATIVO, M.IMOBILIZADO, FORMAT(M.DATA_SAIDA, 'DD/MM/YYYY') AS DS, M.NF_SAIDA, M.DESTINO, " +
                       "M.OPERACAO, M.SOLICITANTE, M.PRAZO_RETORNO, M.PRAZO_EMAIL, M.EMAIL_PARA, M.INTERVALO_EMAIL, " +
                       "FORMAT(M.ULTIMO_EMAIL_ALERTA, 'DD/MM/YYYY') AS UEA " +
                "FROM Movimentacao AS M " +
                "INNER JOIN ATIVOS AS A ON A.IMOBILIZADO = M.IMOBILIZADO " +
                "WHERE NF_ENTRADA IS NULL AND EMAIL_PARA <> NULL AND INTERVALO_EMAIL > 0 " +
                    "AND (ULTIMO_EMAIL_ALERTA IS NULL OR ((DATE() - ULTIMO_EMAIL_ALERTA) > INTERVALO_EMAIL))");
            ResultSet rsStms = stms.executeQuery();

            while (rsStms.next())
            {
                String ativo = rsStms.getString("Ativo");
                String imobilizado = rsStms.getString("Imobilizado");
                String datasaida = rsStms.getString("ds");
                int prazoretorno = rsStms.getInt("PRAZO_RETORNO");

                try
                {
                    data = new Date(format.parse(datasaida).getTime() + prazoretorno);
                } catch (ParseException ex)
                {
                    Logger.getLogger(MontaEmail.class.getName()).log(Level.SEVERE, null, ex);
                }


                String mensagem = "Ativo: <b>" + ativo + "</b><br>";
                mensagem += "Imobilizado: <b>" + imobilizado + "</b><br>";
                mensagem += "Enviado em: <b>" + datasaida + "</b><br>";
                mensagem += "Data limite para retorno: <b><font color='red'>" + format.format(data).toString() + "</font></b><br><br>";
                mensagem += "Ao retornar, enviar uma via da Nota Fiscal para o focal point de ativos.";

                String to = rsStms.getString("Email_Para");
                String subject = "Alerta de retorno de ativo - E-Mail Automático";

                SendMail sm = new SendMail();
                boolean resultado = sm.Enviar(this.usuario, to, subject, mensagem);

                if (resultado)
                {
                    data = new Date();
                    String sql = "UPDATE MOVIMENTACAO SET ULTIMO_EMAIL_ALERTA=#" +
                                      format1.format(data.getTime()).toString() + "# ";

                    try
                    {
                        data = new Date(format.parse(datasaida).getTime());
                    } catch (ParseException ex)
                    {
                        Logger.getLogger(MontaEmail.class.getName()).log(Level.SEVERE, null, ex);
                    }

                    sql += "WHERE IMOBILIZADO='"+imobilizado+"' and data_saida=#"+
                                        format1.format(data.getTime()).toString()+"#";
                    PreparedStatement stms2 = cnx.conexao.prepareStatement(sql);
                    stms2.execute();
                    stms2.close();
                }
            }

            stms.close();
        } catch (SQLException e)
        {
            JOptionPane.showMessageDialog(null, "Houve erro na Thread.\n"+e);
        }
    }
}

Código de ativação da Thread

public class menu extends javax.swing.JFrame {

    String usuario;
    Conexao rs;

    public menu(String user) {
        initComponents();

        usuario = user;
        lUsuario.setText(usuario);

        rs = new Conexao();

        setLocationRelativeTo(null);

        libera_acessos();

        Thread passaEmail = new MontaEmail(usuario);
        passaEmail.start();
        try
        {
            Thread.currentThread().sleep(1000);
        } catch (InterruptedException e) {}
    }
.
.
.

Pq vc não usa o Quartz? Ele já tem isso pronto.

Boa tarde

Dê uma olhada nas classes Timer e TimerTask, caso seja somente agendamento que você precisa elas podem ajudar:

http://mballem.wordpress.com/2011/06/01/agendamento-de-tarefas-com-timertask/
http://www.dsc.ufcg.edu.br/~jacques/cursos/map/html/threads/timer.html
http://docs.oracle.com/javase/7/docs/api/java/util/TimerTask.html

Falou.

Pessoal, consegui resolver o problema.
Usei a dica no nosso amigo Hebert Coelho.
O Quartz funcionou perfeitamente.

Valeu Herbert, muito obrigado.