7 Replies Latest reply on Feb 7, 2013 7:06 PM by meandmycode

    Thread is blocking when using a timed thread with executorservice

    meandmycode
      Hi,

      I originally had the following code:
      execMgr = new ExecutionManagementThread(listener, process);
           execMgr.setDaemon(true);
           execMgr.start();
      The execMgrThread looks like this ( see below). Purpose of this thread is to keep a process with a native command running.

           private static class ExecutionManagementThread extends Thread {
                private boolean finished = false;
                private OperationListener opListener = null;
                private Process process = null;
                /**
                 * Creates a new instance.
                 * 
                 * @param opListener
                 * @param process
                 */
                public ExecutionManagementThread(OperationListener opListener,
                          Process process) {
                     super("CC Execution Management");
                     this.opListener = opListener;
                     this.process = process;
                }
      
                @Override
                public void run() {
                     while (!finished) {
                          try {
                               sleep(250);
                          } catch (InterruptedException ex) {
                          }
                          synchronized (this) {
                               if (opListener != null && opListener.isCanceled()) {
                                    process.destroy();
                                    finished = true;
                               }
                          }
                     }
                }
                
                
      
                public synchronized void setOperationListener(OperationListener ol) {
                     opListener = ol;
                }
      
           }
      However I need this process to be timed meaning it should run for a specific amount of time and then finish. So I decided to use ExecutorService.

      So I created a executorService:
       private static ExecutorService executorService = Executors.newSingleThreadExecutor(new ThreadFactory() {
                     
                     public Thread newThread(Runnable r) {
                          Thread thread = new Thread(r, "ExecutionManagerThread");
                          thread.setDaemon(true);
                   return thread;
                     }
                });
      And instead of extending a Thread for execMgr I use a Runnable:
      private static class ExecutionManangementRunnable implements Runnable{
                
                private boolean finished = false;
                private OperationListener opListener = null;
                private Process process = null;
      
                /**
                 * Creates a new instance.
                 * 
                 * @param opListener
                 * @param process
                 */
                public ExecutionManangementRunnable(OperationListener opListener,
                          Process process) {
                     this.opListener = opListener;
                     this.process = process;
                }
      
                /* (non-Javadoc)
                 * @see java.lang.Runnable#run()
                 */
                public void run() {
                     while (!finished) {
                          try {
                               Thread.sleep(250);
                               
                          } catch (InterruptedException ex) {
                          }
                          synchronized (this) {
                               if (opListener != null && opListener.isCanceled()) {
                                    process.destroy();
                                    finished = true;
                               }
                          }
                     }
                     
                }
                
                public synchronized void setOperationListener(OperationListener ol) {
                     opListener = ol;
                }
                
           }
      Then to create the timed thread I use the following code:
      public static void timedRun(Runnable r , long timeout, TimeUnit unit) throws InterruptedException{
                Future<?> task = executorService.submit(r);
                
                try {
                     task.get(timeout, unit);
                } catch (TimeoutException e) {
                     System.out.println("task got timeout!");
                     //task cancelled in finally
                }catch (ExecutionException e) {
                     System.out.println("task got execution exception");
                }finally{
                     System.out.println("cancel task...");
                     task.cancel(true);
                     System.out.println("task canceled...");
                }
           }
      The above code work in the sense that it created the thread and keep the process alive for a specifc amount of time.
      The problem I have with timedRun is that it blocks. So the runnable is executed but blocks other threads.
      I am suspecting that the last code snippet is not correct. It seems to be waiting for the task to finish or timeout and blocks.
      How can I make the thread execute for a specific time or finish without it blocking?

      ( Sorry for posting so much code but I could not keep it to a small code snippet ( for background info.)

      br,

      //mike
        • 1. Re: Thread is blocking when using a timed thread with executorservice
          Kayaman
          meandmycode wrote:
          I am suspecting that the last code snippet is not correct. It seems to be waiting for the task to finish or timeout and blocks.
          That's what Future.get() does. Blocks until a result is available, or a timeout (if time is specified) occurs.
          If you don't want that to block, you'll need a separate thread for your timedRun.
          1 person found this helpful
          • 2. Re: Thread is blocking when using a timed thread with executorservice
            meandmycode
            ok. Do you mean that I need to change this:

            newSingleThreadExecutor(ThreadFactory threadFactory)

            to:

            newFixedThreadPool(int nThreads, ThreadFactory threadFactory)

            or is there another way of dong this?

            br

            //mikael
            • 3. Re: Thread is blocking when using a timed thread with executorservice
              Kayaman
              meandmycode wrote:
              ok. Do you mean that I need to change this:

              newSingleThreadExecutor(ThreadFactory threadFactory)

              to:

              newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
              No, that has nothing to do with it.
              Your Future.get() call blocks the current thread as it should. If that's something you don't want, then you'll need to run it in a separate thread. How you choose to do that is up to you, but I wouldn't bother with a threadpool or an executor for something as simple as that.
              • 4. Re: Thread is blocking when using a timed thread with executorservice
                meandmycode
                I tried to run it in a separate thread:
                executionMgr = new ExecutionManangementRunnable(listener, process);
                               Callable callable = Executors.callable(executionMgr, null);
                               FutureTask future = new FutureTask(callable);
                               Thread thread = new Thread(future);
                               thread.setDaemon(true);
                               thread.start();
                               
                               try {
                                    future.get(1, TimeUnit.MINUTES);
                               } catch (InterruptedException e) {
                                    // TODO handle catch block
                                    e.printStackTrace();
                               } catch (ExecutionException e) {
                                    // TODO handle catch block
                                    e.printStackTrace();
                               } catch (TimeoutException e) {
                                    // TODO handle catch block
                                    e.printStackTrace();
                               }
                I still get the same problem with main thread being blocked. Does anyone know why?'

                //mikael
                • 5. Re: Thread is blocking when using a timed thread with executorservice
                  jtahlborn
                  meandmycode wrote:
                  I still get the same problem with main thread being blocked. Does anyone know why?'
                  because you are still doing the same thing (calling Future.get() on the main thread).
                  • 6. Re: Thread is blocking when using a timed thread with executorservice
                    Kayaman
                    meandmycode wrote:
                    I still get the same problem with main thread being blocked. Does anyone know why?'
                    In your main thread, start a new thread. Now your main thread won't be blocked. In your new thread, do all the things you're doing now. Voilà!

                    Or don't you know how to handle threads without the higher level constructs (executors etc.)? If so, I'd recommend brushing up on them.
                    • 7. Re: Thread is blocking when using a timed thread with executorservice
                      meandmycode
                      Thanks!

                      No problem I know how I can create a regular thread so the code became the following:

                           Thread thread = new Thread(){
                                     public void run(){
                                          try {
                                                    timedRun(executionMgr,30,TimeUnit.MINUTES);
                                               } catch (InterruptedException e) {
                                                    // TODO handle catch block
                                                    e.printStackTrace();
                                               }
                                     }
                                     };
                                     
                                     thread.start();

                      //mikael