2

I need to run a thread every minute to clean up a table in a DB, I'm using a sleep(1000) inside a while(true) loop. However, I need to clean up the same table if a List's size is bigger than X. I really can't find out how to make that. (except the sleep(1000) way) can you guys please help me?

Here's my code:

public class TrxJanitor implements Runnable {

    private Thread t;
    private List<UUID> idList;

    public List<UUID> getIdList() {
        return idList;
    }

    /* getters and setters*/

       public void start()
       {
          if (t == null)
          {
             t = new Thread(this);
             t.start();
          }
       }

    public void addToJanitorList(UUID id){
        idList.add(id);
    }

    @Override
    public void run() {                 
            System.out.println("Running...");
            EntityManagerFactory emf = Persistence.createEntityManagerFactory("account-pu");                    
            while (true) {
            // create EM tx1 and tx2
                EntityManager em = emf.createEntityManager();

                em.getTransaction().begin();

                System.out.println("Trying to delete from DB...");
                if(!idList.isEmpty()) {
                    for (UUID id : idList) {                
                        em.createNativeQuery("DELETE FROM TrxIdList WHERE Id LIKE '"+id+"'").executeUpdate();
                        System.out.println("DELETED THIS ID: "+id );
                    }
                    idList.removeAll(idList);
                }
                em.getTransaction().commit();
                System.out.println("DATA IN DB:\n");

              // print all lines of table
                @SuppressWarnings("unchecked")
                List<TrxIdList> ids = em.createNativeQuery("SELECT * FROM TrxIdList", TrxIdList.class).getResultList();
                if (!ids.isEmpty()) {
                    System.out.println("DB ROWS:\n");
                    int i = 0;
                    for (TrxIdList id : ids)
                    {
                         System.out.println("TRX_ID: "+id.getId() + " DATA: "+ id.getCreationTs()+"\n");
                         i++;
                    }
                    System.out.println("There are still a total of "+i+" lines in this table!");
                }

                em.close();

                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }

    }


}

And here where I start my thread:

public class PopulateTrxIdTable {

    public static void main(String[] args) {

        TrxJanitor t = new TrxJanitor();
        t.start();
        System.out.println("All records inserted!");        
        System.out.println("Going to sleep!");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {          
                e.printStackTrace();
            }
        System.out.println("Waking up!");       
        System.out.println("DONE!");
        System.out.println("Inserting into DB...");

        insertIntoDb(t);
    }

    private static void insertIntoDb(TrxJanitor t) {

        boolean pair = true;
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("account-pu");

        // create EM 
        EntityManager em1 = emf.createEntityManager();

        em1.getTransaction().begin();

        for (int i=0; i< 10000; i++) {
        //populates DB with the values returned by fillIds()
            if(i%2==0){
                pair = true;
            } else {
                pair = false;
            }
            em1.persist(fillIds(t, pair));

        }
        em1.getTransaction().commit();
        em1.close();
        emf.close();
    }

    private static TrxIdList fillIds(TrxJanitor j, boolean pair) {

        TrxIdList p = new TrxIdList();
        Random rand = new Random();

        //populates de DB with random ids and random dates (dates within range)        
        int randomNum = rand.nextInt((10 - 0) + 1) + 0;
        UUID id = UUID.randomUUID();    
        p.setId(id.toString());
        p.setCreationTs(notToday(randomNum)); //notToday returns a random timestamp
        if (pair) {
            j.addToJanitorList(id);
        }
        return p;

    }

}

How can I alter this so I can add the condition to start the thread when the idList size is bigger than X?

SaintLike
  • 9,119
  • 11
  • 39
  • 69

3 Answers3

0

I would look into the ScheduledExecutorService and have it periodically execute a Runnable. For example, the following code should run your "run" method form your TrxJanitor every minute:

 import static java.util.concurrent.TimeUnit.*;
 public class PopulateTrxIdTable {
   private final ScheduledExecutorService scheduler =
     Executors.newScheduledThreadPool(1);

   public static void main(String[] args) {
     scheduler.schedule(new TrxJanitor(), 1, SECONDS);
   }
 }
Luke Willis
  • 8,429
  • 4
  • 46
  • 79
Minh Nguyen
  • 273
  • 1
  • 4
  • 14
0

You should use a monitor for this task.

It allows you to wait for a specific time on a monitor (note that it has a wait with a timeout overload), the trick is that while you are waiting on a monitor- the wait can be interrupted in two cases- either the time elapses or somebody calls notify on the monitor object.

A basic usage example:

final Object mon = new Object();

// This thread waits on a monitor for 1000msec, unless the other guy wakes him up first...
new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            System.out.println("Sleep 1000");
            synchronized (mon) {
                mon.wait(1000);
            }
        } catch (InterruptedException e) { }
    }
}).start();

// this thread will flip a coin and wake up the waiting thread if it hits tails
new Thread(new Runnable() {
    @Override
    public void run() {
        if (new Random().nextBoolean()) {
            System.out.println("Wake early!");
            synchronized (mon) {
                mon.notify();
            }
        }
    }
}).start();

Have a look at this answer for a more elaboration.

Community
  • 1
  • 1
Vitaliy
  • 8,044
  • 7
  • 38
  • 66
0

You can create a ScheduledExecutorService like Minh Nguyen suggested, but use the logic discribed in this answer, for your task to reschedule itself according to your changing requirements.

Community
  • 1
  • 1
PeterK
  • 1,697
  • 10
  • 20