Android Open Source - netmbuddy Multi Thread Runner






From Project

Back to project page netmbuddy.

License

The source code is released under:

------- Default ------- Copyright (C) 2012, 2013, 2014 Younghyung Cho. <yhcting77@gmail.com> All rights reserved. This file is part of NetMBuddy This program is licensed under the FreeBSD license R...

If you think the Android project netmbuddy listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/******************************************************************************
 * Copyright (C) 2012, 2013, 2014/*ww  w. j  a v  a  2 s  .c om*/
 * Younghyung Cho. <yhcting77@gmail.com>
 * All rights reserved.
 *
 * This file is part of NetMBuddy
 *
 * This program is licensed under the FreeBSD license
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * The views and conclusions contained in the software and documentation
 * are those of the authors and should not be interpreted as representing
 * official policies, either expressed or implied, of the FreeBSD Project.
 *****************************************************************************/

package free.yhc.netmbuddy.model;

import static free.yhc.netmbuddy.utils.Utils.eAssert;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

import android.os.Handler;
import free.yhc.netmbuddy.utils.Utils;

// [ Naming Convention ]
// Runnable => Job
// Thread   => Task
public class MultiThreadRunner {
    private static final boolean DBG = false;
    private static final Utils.Logger P = new Utils.Logger(MultiThreadRunner.class);

    private final Handler               mOwner;
    private final Object                mQLock      = new Object();
    private final LinkedList<Job<?>>    mReadyQ     = new LinkedList<Job<?>>();
    private final LinkedList<Task<?>>   mRunQ       = new LinkedList<Task<?>>();
    private final int                   mMaxConcur;
    private final AtomicBoolean         mCancelled  = new AtomicBoolean(false);
    private final AtomicFloat           mProgress   = new AtomicFloat(0);
    private final AtomicReference<OnProgressListener> mProgListener
        = new AtomicReference<OnProgressListener>(null);
    private final AtomicReference<OnDoneListener> mDoneListener
        = new AtomicReference<OnDoneListener>(null);

    // For debugging purpose.
    private int  mSeqN   = 0;

    public interface OnProgressListener {
        /**
         *
         * @param prog
         *   accumulated value of each Job's progress weight.
         */
        void onProgress(float prog);
    }

    public interface OnDoneListener {
        void onDone(MultiThreadRunner mtrunner, boolean cancelled);
    }

    public static abstract class Job<R> {
        private final boolean _mInterruptOnCancel;
        private final float _mProgWeight;
        private final int   _mTaskPriority = -1; // not used yet.

        private Handler _mOwner     = null;
        private OnProgressListener _mProgListener = null;

        public Job(boolean interruptOnCancel, float progWeight) {
            _mProgWeight = progWeight;
            _mInterruptOnCancel = true; // default is true.
        }

        public Job(float progWeight) {
            this(true, progWeight);
        }

        public Job() {
            this(0);
        }

        /**
         * @hide
         */
        final void
        setOwner(Handler owner) {
            // Setting only ONCE is allowed to avoid synch. issue.
            eAssert(null == _mOwner);
            _mOwner = owner;
        }

        /**
         * @hide
         */
        final void
        setProgListener(OnProgressListener listener) {
            // Setting only ONCE is allowed to avoid synch. issue.
            eAssert(null == _mProgListener);
            _mProgListener = listener;
        }

        /**
         * @hide
         */
        final boolean
        getInterruptOnCancel() {
            return _mInterruptOnCancel;
        }

        final int
        getTaskPriority() {
            return _mTaskPriority;
        }

        final float
        getProgWeight() {
            return _mProgWeight;
        }

        protected final void
        publishProgress(float prog) {
            // NOTE
            // _mProgListener and _mOwner can be set only once.
            // So, synch. issue can be ignored here.
            if (null != _mProgListener) {
                final float overallProg = prog * _mProgWeight;
                _mOwner.post(new Runnable() {
                    @Override
                    public void
                    run() {
                        _mProgListener.onProgress(overallProg);
                    }
                });
            }
        }

        public void
        onPreRun() { }

        abstract public R
        doJob();

        public void
        cancel() { }

        public void
        onCancelled() { }

        public void
        onPostRun(R result) { }

        public void
        onProgress(int prog) { }
    }

    private static class Task<R> extends BGTask<R> {
        private final MultiThreadRunner _mMtrunner;
        private final Job<R>    _mJob;

        // NOTE
        // To workaround Android GB Framework bug regarding AsyncTask.
        // On GB Framework, it is NOT guaranteed that onCancelled() is called after returning from doInBackground().
        // This is based on experimental result on Moto Bionic.
        private final boolean   _mJobDone = false;

        private boolean
        isOwnerThread() {
            return _mMtrunner.getOwner().getLooper().getThread() == Thread.currentThread();
        }

        Task(MultiThreadRunner mtrunner,
             Job<R> job,
             Handler owner) {
            super(owner);
            _mMtrunner = mtrunner;
            _mJob = job;
        }

        Job<R>
        getJob() {
            return _mJob;
        }

        public void
        cancel() {
            eAssert(isOwnerThread());
            _mJob.cancel();
            super.cancel(_mJob.getInterruptOnCancel());
        }

        @Override
        protected void
        onPreRun() {
            eAssert(isOwnerThread());
            _mJob.onPreRun();
        }

        @Override
        protected void
        onCancelled() {
            eAssert(isOwnerThread());
            _mJob.onCancelled();
            _mMtrunner.onTaskDone(Task.this, true);
        }

        @Override
        protected void
        onPostRun(final R r) {
            eAssert(isOwnerThread());
            _mJob.onPostRun(r);
            _mMtrunner.onTaskDone(this, false);
        }

        @Override
        protected R
        doAsyncTask() {
            R r = null;
            r = _mJob.doJob();
            return r;
        }
    }

    private void
    mustRunOnOwnerThread() {
        eAssert(mOwner.getLooper().getThread() == Thread.currentThread());
    }

    private float
    updateProgress(float amountOfProgress) {
        float f = mProgress.get();
        mProgress.set(f + amountOfProgress);
        return mProgress.get();
    }

    private void
    publishProgress(float prog) {
        OnProgressListener listener = mProgListener.get();
        if (null != listener)
            listener.onProgress(prog);

    }

    private void
    publishDone(boolean cancelled) {
        OnDoneListener listener = mDoneListener.get();
        if (null != listener)
            listener.onDone(this, cancelled);
    }

    /**
     * mQLock should be held.
     * @return
     */
    private boolean
    isAllJobsDoneLocked() {
        return mReadyQ.isEmpty() && mRunQ.isEmpty();
    }

    /**
     * mQLock should be held.
     * @param job
     */
    private void
    runJobLocked(Job<?> job) {
        // TODO
        // Is there any to instantiate generic 'task' whose generic type is
        //   same with generic type of 'job' instead of raw-type?
        Task<?> t = new Task(this, job, mOwner);
        mRunQ.addLast(t);
        t.run();
    }

    private void
    onTaskDone(final Task<?> task, final boolean cancelled) {
        mustRunOnOwnerThread();
        //logD("Run TaskDone START : " + task.getName());

        mOwner.post(new Runnable() {
            @Override
            public void
            run() {
                if (!mCancelled.get())
                    publishProgress(updateProgress(task.getJob().getProgWeight()));
            }
        });

        synchronized (mQLock) {
            mRunQ.remove(task);
            eAssert(mRunQ.size() < mMaxConcur);

            if (!mReadyQ.isEmpty())
                runJobLocked(mReadyQ.removeFirst());

            if (isAllJobsDoneLocked()) {
                publishDone(mCancelled.get());
                mQLock.notifyAll();
            }
        }
        //logD("Run TaskDone END : " + task.getName());
    }

    public MultiThreadRunner(Handler ownerHandler,
                             int nrMaxConcurrent) {
        mOwner = ownerHandler;
        mMaxConcur = nrMaxConcurrent;
    }

    public Handler
    getOwner() {
        return mOwner;
    }

    public void
    setOnDoneListener(OnDoneListener listener) {
        mDoneListener.set(listener);
    }

    public void
    setOnProgressListener(OnProgressListener listener) {
        mProgListener.set(listener);
    }

    public void
    appendJob(Job<?> job) {
        job.setOwner(mOwner);
        job.setProgListener(new OnProgressListener() {
            @Override
            public void
            onProgress(float prog) {
                mustRunOnOwnerThread();
                // 'prog' value is calculated value based on Job's progressWeight.
                publishProgress(updateProgress(prog));
            }
        });

        synchronized (mQLock) {
            if (mRunQ.size() < mMaxConcur)
                runJobLocked(job);
            else
                mReadyQ.addLast(job);
        }
    }

    public void
    clearCancelledState() {
        mCancelled.set(false);
    }

    public void
    setProgress(float v) {
        mProgress.set(v);
    }

    public void
    cancel() {
        mCancelled.set(true);
        synchronized (mQLock) {
            mReadyQ.clear();
            Iterator<Task<?>> iter = mRunQ.iterator();
            while (iter.hasNext())
                iter.next().cancel();
        }
    }

    public void
    waitAllDone() throws InterruptedException {
        synchronized (mQLock) {
            if (!isAllJobsDoneLocked())
                mQLock.wait();
        }
    }
}




Java Source Code List

free.yhc.netmbuddy.DiagAsyncTask.java
free.yhc.netmbuddy.Err.java
free.yhc.netmbuddy.FragmentPagerAdapterEx.java
free.yhc.netmbuddy.ImportShareActivity.java
free.yhc.netmbuddy.ImportShareContentActivity.java
free.yhc.netmbuddy.ImportShareFileActivity.java
free.yhc.netmbuddy.LockScreenActivity.java
free.yhc.netmbuddy.MusicsActivity.java
free.yhc.netmbuddy.MusicsAdapter.java
free.yhc.netmbuddy.PlaylistActivity.java
free.yhc.netmbuddy.PlaylistAdapter.java
free.yhc.netmbuddy.VideoPlayerActivity.java
free.yhc.netmbuddy.YTMPActivity.java
free.yhc.netmbuddy.YTMPApp.java
free.yhc.netmbuddy.YTMPPreferenceActivity.java
free.yhc.netmbuddy.YTPlaylistSearchActivity.java
free.yhc.netmbuddy.YTPlaylistSearchAdapter.java
free.yhc.netmbuddy.YTPlaylistSearchFragment.java
free.yhc.netmbuddy.YTSearchActivity.java
free.yhc.netmbuddy.YTSearchAdapter.java
free.yhc.netmbuddy.YTSearchFragment.java
free.yhc.netmbuddy.YTSearchPagerAdapter.java
free.yhc.netmbuddy.YTVideoSearchActivity.java
free.yhc.netmbuddy.YTVideoSearchAdapter.java
free.yhc.netmbuddy.YTVideoSearchAuthorActivity.java
free.yhc.netmbuddy.YTVideoSearchFragment.java
free.yhc.netmbuddy.YTVideoSearchKeywordActivity.java
free.yhc.netmbuddy.YTVideoSearchPlaylistActivity.java
free.yhc.netmbuddy.db.ColPlaylist.java
free.yhc.netmbuddy.db.ColVideoRef.java
free.yhc.netmbuddy.db.ColVideo.java
free.yhc.netmbuddy.db.DBHelper.java
free.yhc.netmbuddy.db.DBHistory.java
free.yhc.netmbuddy.db.DBManager.java
free.yhc.netmbuddy.db.DBUpgrader.java
free.yhc.netmbuddy.db.DBUtils.java
free.yhc.netmbuddy.db.DB.java
free.yhc.netmbuddy.model.AtomicFloat.java
free.yhc.netmbuddy.model.BGTask.java
free.yhc.netmbuddy.model.HttpUtils.java
free.yhc.netmbuddy.model.KBLinkedList.java
free.yhc.netmbuddy.model.MultiThreadRunner.java
free.yhc.netmbuddy.model.NetLoader.java
free.yhc.netmbuddy.model.NotiManager.java
free.yhc.netmbuddy.model.Policy.java
free.yhc.netmbuddy.model.RTState.java
free.yhc.netmbuddy.model.SearchSuggestionProvider.java
free.yhc.netmbuddy.model.UnexpectedExceptionHandler.java
free.yhc.netmbuddy.model.YTConstants.java
free.yhc.netmbuddy.model.YTDownloader.java
free.yhc.netmbuddy.model.YTFeed.java
free.yhc.netmbuddy.model.YTHacker.java
free.yhc.netmbuddy.model.YTPlayerLifeSupportService.java
free.yhc.netmbuddy.model.YTPlayerUI.java
free.yhc.netmbuddy.model.YTPlayerVideoListAdapter.java
free.yhc.netmbuddy.model.YTPlayerVideoListManager.java
free.yhc.netmbuddy.model.YTPlayer.java
free.yhc.netmbuddy.model.YTPlaylistFeed.java
free.yhc.netmbuddy.model.YTSearchHelper.java
free.yhc.netmbuddy.model.YTVideoFeed.java
free.yhc.netmbuddy.scmp.DNLoop.java
free.yhc.netmbuddy.scmp.SCElemChar.java
free.yhc.netmbuddy.scmp.SCElemI.java
free.yhc.netmbuddy.scmp.SCElemSStr.java
free.yhc.netmbuddy.scmp.SCElemSTok.java
free.yhc.netmbuddy.scmp.SCElemTok.java
free.yhc.netmbuddy.scmp.SCElem.java
free.yhc.netmbuddy.scmp.SCmpPolicy.java
free.yhc.netmbuddy.scmp.SCmp.java
free.yhc.netmbuddy.share.ExporterPlaylist.java
free.yhc.netmbuddy.share.ImporterPlaylist.java
free.yhc.netmbuddy.share.Importer.java
free.yhc.netmbuddy.share.Json.java
free.yhc.netmbuddy.share.Share.java
free.yhc.netmbuddy.utils.BookmarkListAdapter.java
free.yhc.netmbuddy.utils.FileUtils.java
free.yhc.netmbuddy.utils.ImageUtils.java
free.yhc.netmbuddy.utils.ReportUtils.java
free.yhc.netmbuddy.utils.SimilarTitlesListAdapter.java
free.yhc.netmbuddy.utils.UiUtils.java
free.yhc.netmbuddy.utils.Utils.java
free.yhc.netmbuddy.utils.YTUtils.java