Package org.agilewiki.jactor2.core.impl.mtPlant

Source Code of org.agilewiki.jactor2.core.impl.mtPlant.ReactorPoolThreadManager

package org.agilewiki.jactor2.core.impl.mtPlant;

import org.agilewiki.jactor2.core.impl.mtReactors.MigrationException;
import org.agilewiki.jactor2.core.impl.mtReactors.PoolThreadReactorMtImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicReference;

/**
* The ReactorPoolThreadManager is used to process a queue of Reactor's
* that have non-empty inboxes.
* ReactorPoolThreadManager is a thread pool, but it has a simplified API and
* assumes that the thread pool has a fixed number of threads.
* ReactorPoolThreadManager is also responsible for assigning the threadReference
* when a Reactor is run.
*/
public final class ReactorPoolThreadManager {
    final Logger logger = LoggerFactory
            .getLogger(ReactorPoolThreadManager.class);

    /**
     * The taskRequest semaphore is used to wake up a thread
     * when there is a Reactor which hasWork.
     */
    final private Semaphore taskRequest = new Semaphore(0);

    /**
     * The reactors queue holds the reactors which have messages to be processed.
     */
    final private ConcurrentLinkedQueue<PoolThreadReactorMtImpl> reactors = new ConcurrentLinkedQueue<PoolThreadReactorMtImpl>();

    /**
     * When closing is true, the threads exit as they finish their current activity.
     */
    private boolean closing = false;

    /**
     * The threadCount is the number of threads in the thread pool.
     */
    private int threadCount;

    /**
     * The threads in the thread pool.
     */
    private Thread threads[] = null;

    /**
     * Create a ReactorPoolThreadManager
     *
     * @param _threadCount   The number of threads to be created.
     * @param _threadFactory Used to create the threads.
     */
    public ReactorPoolThreadManager(final int _threadCount,
            final ThreadFactory _threadFactory) {
        this.threadCount = _threadCount;
        final Runnable runnable = new Runnable() {
            @Override
            public void run() {
                final ReactorPoolThread currentThread = (ReactorPoolThread) Thread
                        .currentThread();
                while (true) {
                    try {
                        taskRequest.acquire();
                        PoolThreadReactorMtImpl reactor = reactors.poll();
                        if (reactor != null) {
                            AtomicReference<Thread> threadReference = reactor
                                    .getThreadReference();
                            if ((threadReference.get() == null)
                                    && threadReference.compareAndSet(null,
                                            currentThread)) {
                                currentThread.setCurrentReactor(reactor);
                                while (true) {
                                    try {
                                        reactor.run();
                                    } catch (final MigrationException me) {
                                        final boolean hasWork = reactor
                                                .hasWork();
                                        threadReference.set(null);
                                        if (reactor.isIdler() || hasWork
                                                || reactor.hasConcurrent()) {
                                            execute(reactor);
                                        }
                                        reactor = me.reactor;
                                        threadReference = reactor
                                                .getThreadReference();
                                        currentThread
                                                .setCurrentReactor(reactor);
                                        continue;
                                    } catch (final Throwable e) {
                                        logger.error(
                                                "Exception thrown by a targetReactor's run method",
                                                e);
                                    }
                                    final boolean hasWork = reactor.hasWork();
                                    threadReference.set(null);
                                    if (hasWork || reactor.hasConcurrent()) {
                                        execute(reactor);
                                    }
                                    break;
                                }
                                currentThread.setCurrentReactor(null);
                            }
                        }
                    } catch (final InterruptedException e) {
                    }
                    currentThread.setCurrentReactor(null);
                    if (closing) {
                        return;
                    }
                }
            }
        };
        threads = new Thread[this.threadCount];
        for (int c = 0; c < _threadCount; c++) {
            final Thread t = _threadFactory.newThread(runnable);
            threads[c] = t;
            t.start();
        }
    }

    /**
     * Begin running a targetReactor.
     *
     * @param _reactor The run method is to be called by the selected thread.
     */
    public final void execute(final PoolThreadReactorMtImpl _reactor) {
        if (closing) {
            return;
        }
        reactors.add(_reactor);
        taskRequest.release();
    }

    /**
     * The close method is used to stop all the threads as they become idle.
     * This method sets a flag to indicate that the thread should stop
     * and then wakes up all the threads.
     */
//    * This method only returns after all the threads have died.
    public final void close() {
        if (closing) {
            return;
        }
        closing = true;
        taskRequest.release(threadCount);
        final Thread ct = Thread.currentThread();
        for (final Thread t : threads) {
            if (ct != t) {
                t.interrupt();
            }
        }
        /*
        for (final Thread t : threads) {
            if (ct != t) {
                try {
                    t.join();
                } catch (final InterruptedException e) {
                }
            }
        }
        // Release the references to the thread array...
        threads = null;
        */
    }
}
TOP

Related Classes of org.agilewiki.jactor2.core.impl.mtPlant.ReactorPoolThreadManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.