All Downloads are FREE. Search and download functionalities are using the official Maven repository.

xapi.process.impl.ConcurrencyServiceAbstract Maven / Gradle / Ivy

Go to download

Everything needed to run a comprehensive dev environment. Just type X_ and pick a service from autocomplete; new dev modules will be added as they are built. The only dev service not included in the uber jar is xapi-dev-maven, as it includes all runtime dependencies of maven, adding ~4 seconds to build time, and 6 megabytes to the final output jar size (without xapi-dev-maven, it's ~1MB).

The newest version!
package xapi.process.impl;

import static xapi.util.X_Debug.debug;

import java.lang.Thread.State;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Iterator;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;

import javax.inject.Provider;

import xapi.collect.impl.AbstractMultiInitMap;
import xapi.log.X_Log;
import xapi.process.api.ConcurrentEnvironment;
import xapi.process.api.ConcurrentEnvironment.Priority;
import xapi.process.api.Process;
import xapi.process.api.ProcessController;
import xapi.process.service.ConcurrencyService;
import xapi.util.X_Runtime;
import xapi.util.X_Util;
import xapi.util.api.ConvertsValue;
import xapi.util.api.ReceivesValue;

public abstract class ConcurrencyServiceAbstract implements ConcurrencyService{

  protected class WrappedRunnable implements Runnable {

    private Runnable core;

    public WrappedRunnable(Runnable core) {
      this.core = core;
    }

    @Override
    public void run() {

      core.run();
      destroy(Thread.currentThread(), threadFlushTime());

      //Now that we've finished the job we were told to do,
      //let's attempt to reuse our current thread


      //We should choose how to "steal work" wisely,
      //using an algorithm which has known ETA times,
      //so a thread which knows about an upcoming task
      //can choose to reject long-running tasks;

      //This will require coordination around the workload of other threads.
      //If there is already one thread spinning, looking for work,
      //and that thread is spending less than X % of time working,
      //then we can take on any job.

      //There will also be a necessary priority calculation;
      //A big pending high priority job should take any live threads,
      //and we can spin up more replacements for other tasks if needed.

      //In order to prevent attention-starvation, a task's priority will get
      //bumped up if it has to wait too long.

      //Using a min-max latency and eta will help in determining the best job
      //to take.

      //First, check for immediate jobs scheduled by the current thread.
      //this will help in cases when a thread simply wants to yield,
      //or when a forking process wants to continue immediately,
      //or when gluing together methods into a process.


      //Next, check for high priority jobs scheduled by any thread.
      //Anything with a timeout at or near expiration should be taken.
      //If there are known tiny jobs available with a known eta less than
      //the wait time for the high priority job, that job should be taken as well.
      //If no such jobs exist, scan the work queue to elevate any starving tasks

      //If no high priority jobs are waiting, scan the work queue for either
      //a) work to do; if timeout ~expired, take and run immediately
      //b) tasks to elevate;
      //the iterator supplied when looking for work should elevate on its own.

      //if no task is found, die unless you are the last thread.
      //if timeout > now, drain the iterator to make sure anything needing
      //elevation gets it.
    }

  }

  protected class EnviroMap extends
    AbstractMultiInitMap {

    public EnviroMap() {
      super(new ConvertsValue() {
        @Override
        public String convert(Thread from) {
          return from.getName();
        }
      });
    }

    @Override
    protected ConcurrentEnvironment initialize(Thread key, UncaughtExceptionHandler params) {
      if (key.getState() == State.TERMINATED) {
        //send an exception...
        params.uncaughtException(key, new ThreadDeath());
      }
      if (key.isInterrupted()) {
        params.uncaughtException(key, new InterruptedException());
      }
      X_Log.debug("Initializing Concurrent Environment", key);
      return initializeEnvironment(key, params);
    }
    @Override
    protected UncaughtExceptionHandler defaultParams() {
      return Thread.currentThread().getUncaughtExceptionHandler();
    }
  }


  protected abstract ConcurrentEnvironment initializeEnvironment(Thread key, UncaughtExceptionHandler params);

  protected int threadFlushTime() {
    return 2000;
  }

  private final EnviroMap environments = initMap();

  private AtomicInteger threadCount = new AtomicInteger();

  @Override
  public Thread newThread(Runnable cmd) {
    WrappedRunnable wrapped = wrap(cmd);
    Thread childThread = new Thread(wrapped);
    childThread.setName(cmd.getClass().getName()+"_"+threadCount.incrementAndGet());
    Thread running = Thread.currentThread();
    ConcurrentEnvironment enviro = environments.get(running, running.getUncaughtExceptionHandler());
    enviro.pushThread(childThread);
    return childThread;
  }

  /**
   * Allow all subclasses to wrap Runnables for custom behavior.
   * @param cmd - The supplied Runnable to execute.
   * @return - A wrapped Runnable, or cmd if not desired.
   *
   * This method is very useful for running benchmarks or testing assertions.
   */
  protected WrappedRunnable wrap(Runnable cmd) {
    if (cmd instanceof WrappedRunnable)
      return (WrappedRunnable)cmd;
    return new WrappedRunnable(cmd);
  }

  protected ConcurrentEnvironment currentEnvironment() {
    Thread running = Thread.currentThread();
    return environments.get(running, running.getUncaughtExceptionHandler());
  }

  protected EnviroMap initMap() {
    return new EnviroMap();
  }

  @Override
  public  ProcessController newProcess(Process process) {
    return new ProcessController(process);
  }

  @Override
  public  void resolve(final Future future, final ReceivesValue receiver) {
    if (future.isDone()) {
      callback(future, receiver);
      return;
    }
    //The future isn't done.  Let's push a task into the enviro.
    Thread otherThread = getFuturesThread();
    ConcurrentEnvironment enviro = environments.get(otherThread, otherThread.getUncaughtExceptionHandler());
    enviro.monitor(Priority.Low, new Provider() {
      @Override
      public Boolean get() {
        return future.isDone();
      }
    }, new Runnable() {
      @Override
      public void run() {
        callback(future, receiver);
      }
    });
  }

  /**
   * Allows multi-threaded environments to have a single thread dedicated to
   * monitoring futures for completion.
   * @return - The thread to be used for monitoring futures
   */
  protected Thread getFuturesThread() {
    return Thread.currentThread();
  }

  protected  void callback(Future future, ReceivesValue receiver) {
    try {
      receiver.set(future.get());
      return;
    } catch (InterruptedException e) {
      debug(e);
      Thread.interrupted();
    } catch (ExecutionException e) {
      debug(e);
      throw X_Util.rethrow(X_Util.unwrap(e));
    }
  }

  @Override
  @SuppressWarnings("deprecation")
  public boolean kill(Thread thread, int timeout) {
    if (destroy(thread, timeout))
      return true;
    try {
      thread.interrupt();
      return false;
    }catch (Exception e) {
      thread.stop();
      return false;
    }
  }

  private boolean destroy(Thread thread, int timeout) {
    if (environments.hasKey(thread.getName())) {
      ConcurrentEnvironment enviro = environments.get(thread, thread.getUncaughtExceptionHandler());
      boolean success = enviro.destroy(timeout);
      environments.removeValue(thread.getName());
      return success;
    }
    return true;
  }

  @Override
  public boolean trySleep(float millis) {
    if (Thread.interrupted())
      return false;
    float leftover = millis - ((int)millis);
    try {
      Thread.sleep((long)millis, (int)(leftover * 1000000));
      return true;
    }catch (InterruptedException e) {
      Thread.interrupted();
      return false;
    }
  }

  @Override
  public boolean flush(Thread thread, int timeout) {
    ConcurrentEnvironment enviro = environments.getValue(thread.getName());
    if (thread == Thread.currentThread()) {
      if (enviro == null)
        return true;// nothin' to do here!
      long deadline = System.currentTimeMillis()+timeout;
      while (enviro.flush((int)(deadline-System.currentTimeMillis()))) {
        int timeLeft = (int)(deadline-System.currentTimeMillis());
        if (timeLeft<1)
          return false;
        //join a thread, if available
        Iterator iter = enviro.getThreads().iterator();
        try {
          Thread next;
          synchronized (enviro) {
            if (iter.hasNext()) {
              next = iter.next();
              iter.remove();
            }else
              return true;
          }

        if (next != null)
          next.join(timeLeft);
        } catch (InterruptedException e) {
          destroy(Thread.currentThread(), timeLeft);
          Thread.currentThread().interrupt();
        }
        if (System.currentTimeMillis()>deadline)
          return false;
      }
      return true;
    }else {
      if (enviro != null)
        enviro.scheduleFlush(timeout);
      return false;
    }
  }

  @Override
  public double now() {
    return System.currentTimeMillis();
  }

  @Override
  public double threadStartTime(Thread thread) {
    return environments.get(thread, thread.getUncaughtExceptionHandler()).startTime();
  }

  public boolean isMultiThreaded() {
    return X_Runtime.isMultithreaded();
  }


  @Override
  public void runDeferred(Runnable cmd) {
    ConcurrentEnvironment enviro = currentEnvironment();
    enviro.pushDeferred(cmd);
  }

  @Override
  public void runEventually(Runnable cmd) {
    ConcurrentEnvironment enviro = currentEnvironment();
    enviro.pushEventually(cmd);
  }

  @Override
  public void runFinally(Runnable cmd) {
    ConcurrentEnvironment enviro = currentEnvironment();
    enviro.pushFinally(cmd);
  }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy