/** Spawn a thread to wait for all the Being threads to finish. */ private void joinBeingsTasks() { // First, initialize mExitBarrier that's used as an exit // barrier to ensure the waiter thread doesn't finish until // all the BeingTasks finish. mExitBarrier = new CountDownLatch(Options.instance().numberOfBeings()); // Create/start a waiter thread that uses mExitBarrier to wait // for all the BeingTasks to finish. After they are all // finished then tell the UI thread this simulation is done. new Thread( new Runnable() { @Override public void run() { try { // Wait for all BeingTasks to stop gazing. mExitBarrier.await(); } catch (Exception e) { Log.d(TAG, "joinBeingTasks() received exception"); // If we get interrupted while waiting, stop // everything. shutdown(); } finally { // Tell the UI thread this simulation is done. mView.get().done(); } } }) .start(); }
/** * This method is called each time a Being acquires a Palantir. Since each Being is a Java Thread, * it will be called concurrently from different threads. This method increments the number of * threads gazing and checks that the number of threads gazing does not exceed the number of * Palantiri in the simulation using an AtomicLong object instantiated above (mGazingThreads). If * the number of gazing threads exceeds the number of Palantiri, this thread will call shutdown * and return false. * * @return false if the number of gazing threads is greater than the number of Palantiri, * otherwise true. */ private boolean incrementGazingCountAndCheck(PalantiriPresenter presenter) { final long numberOfGazingThreads = presenter.mGazingTasks.incrementAndGet(); if (numberOfGazingThreads > Options.instance().numberOfPalantiri()) { presenter.shutdown(); return false; } else return true; }
/** * This method is called when the user asks to start the simulation in the context of the main UI * Thread. It creates the designated number of Palantiri and adds them to the PalantiriManager. It * then creates a Thread for each Being and has each Being attempt to acquire a Palantir for * gazing, mediated by the PalantiriManager. The BeingTheads call methods from the * MVP.RequiredViewOps interface to visualize what is happening to the user. */ @Override public void start() { // Initialize the Palantiri. getModel().makePalantiri(Options.instance().numberOfPalantiri()); // Initialize the count of the number of threads Beings use to gaze. mGazingTasks = new AtomicLong(0); // Show the Beings on the UI. mView.get().showBeings(); // Show the palantiri on the UI. mView.get().showPalantiri(); // Spawn a thread that waits for all the Being threads to finish. joinBeingsTasks(); // Create and execute an AsyncBeingTask for each Being. Log.i(TAG, "Before createAndExecuteBeingsTasks"); createAndExecuteBeingsTasks(Options.instance().numberOfBeings()); Log.i(TAG, "After createAndExecuteBeingsTasks"); }
/** * This method is called when the user asks to start the simulation in the context of the main UI * Thread. It creates the designated number of Palantiri and adds them to the PalantiriManager. It * then creates a Thread for each Being and has each Being attempt to acquire a Palantir for * gazing, mediated by the PalantiriManager. The BeingTheads call methods from the * MVP.RequiredViewOps interface to visualize what is happening to the user. */ @Override public void start() { // Initialize the PalantiriManager. getModel().makePalantiri(Options.instance().numberOfPalantiri()); // Initialize the count of the number of threads Beings use to // gaze. mGazingThreads = new AtomicLong(0); // Show the Beings on the UI. mView.get().showBeings(); // Show the palantiri on the UI. mView.get().showPalantiri(); // Create and start a BeingThread for each Being. beginBeingsThreads(Options.instance().numberOfBeings()); // Start a thread to wait for all the Being threads to finish // and then inform the View layer that the simulation is done. waitForBeingsThreads(); }
/** * Hook method called when a new instance of PalantiriPresenter is created. One time * initialization code goes here, e.g., storing a WeakReference to the View layer and initializing * the Model layer. * * @param view A reference to the View layer. */ @Override public void onCreate(MVP.RequiredViewOps view) { // Set the WeakReference. mView = new WeakReference<>(view); // Invoke the special onCreate() method in GenericPresenter, // passing in the PalantiriModel class to instantiate/manage // and "this" to provide this MVP.RequiredModelOps instance. super.onCreate(PalantiriModel.class, this); // Get the intent used to start the Activity. final Intent intent = view.getIntent(); // Initialize the Options singleton using the extras contained // in the intent. if (Options.instance().parseArgs(view.getActivityContext(), makeArgv(intent)) == false) Utils.showToast(view.getActivityContext(), "Arguments were incorrect"); // A runtime configuration change has not yet occurred. mConfigurationChangeOccurred = false; }
/** Perform the Being gazing logic. */ @Override public Void doInBackground(PalantiriPresenter... presenters) { // Don't start the threads immediately. Utils.pauseThread(500); // Initialize local variables. int i = 0; Palantir palantir = null; final PalantiriPresenter presenter = presenters[0]; // Try to gaze at a palantir the designated number of times. for (; i < Options.instance().gazingIterations(); ++i) try { // Break out of the loop if the BeingAsyncTask has // been cancelled. // you fill in here by replacing "false" with // the appropriate method call to an AsyncTask method. if (isCancelled()) { // If we've been instructed to stop gazing, notify // the UI and exit gracefully. presenter.mView.get().threadShutdown(mIndex); break; } // Show that we're waiting on the screen. // you fill in here with the appropriate // call to an AsyncTask method. publishProgress(presenter.mView.get().markWaiting(mIndex)); // Get a Palantir - this call blocks if there are no // available Palantiri. palantir = presenter.getModel().acquirePalantir(); if (palantir == null) Log.d( TAG, "Received a null palantir in " + Thread.currentThread().getId() + " for Being " + mIndex); // Make sure we were supposed to get a Palantir. if (!incrementGazingCountAndCheck(presenter)) break; // Mark it as used on the screen. // you fill in here with the appropriate // call to an AsyncTask method. publishProgress(presenter.mView.get().markUsed(palantir.getId())); // Show that we're gazing on the screen. // you fill in here with the appropriate // call to an AsyncTask method. publishProgress(presenter.mView.get().markGazing(mIndex)); // Gaze at my Palantir for the alloted time. palantir.gaze(); // Show that we're no longer gazing. // you fill in here with the appropriate // call to an AsyncTask method. publishProgress(presenter.mView.get().markIdle(mIndex)); Utils.pauseThread(500); // Mark the Palantir as being free. // you fill in here with the appropriate call // to an AsyncTask method. publishProgress(presenter.mView.get().markFree(palantir.getId())); Utils.pauseThread(500); // Tell the double-checker that we're about to // give up a Palantir. decrementGazingCount(presenter); } catch (Exception e) { Log.d(TAG, "Exception caught in index " + mIndex); // If we're interrupted by an exception, notify the UI and // exit gracefully. presenter.mView.get().threadShutdown(mIndex); } finally { // Give it back to the manager. presenter.getModel().releasePalantir(palantir); } Log.d( TAG, "Thread " + mIndex + " has finished " + i + " of its " + Options.instance().gazingIterations() + " gazing iterations"); return (Void) null; }