org.jsl.collider.ThreadPool Maven / Gradle / Ivy
/*
* Copyright (C) 2013 Sergey Zubarev, [email protected]
*
* This file is a part of JS-Collider framework.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
package org.jsl.collider;
import java.util.concurrent.atomic.AtomicReferenceArray;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ThreadPool
{
public static abstract class Runnable
{
public volatile Runnable nextThreadPoolRunnable;
public abstract void runInThreadPool();
}
private static class Sync extends AbstractQueuedSynchronizer
{
private final int m_maxState;
public Sync( int maxState )
{
m_maxState = maxState;
}
protected final int tryAcquireShared( int acquires )
{
for (;;)
{
int state = getState();
int newState = (state - 1);
if ((newState < 0) || compareAndSetState(state, newState))
return newState;
}
}
protected final boolean tryReleaseShared( int releases )
{
for (;;)
{
int state = getState();
if (state == m_maxState)
return false;
if (compareAndSetState(state, state+releases))
return true;
}
}
}
private class Worker extends Thread
{
public void run()
{
final String name = m_name + "-" + getId();
setName( name );
if (s_logger.isLoggable(Level.FINE))
s_logger.log( Level.FINE, name + ": started." );
int idx = 0;
while (m_run)
{
m_sync.acquireShared(1);
int cc = m_contentionFactor;
for (;;)
{
final Runnable runnable = getNext( idx );
if (runnable == null)
{
if (--cc == 0)
break;
}
else
{
runnable.runInThreadPool();
cc = m_contentionFactor;
}
idx++;
idx %= m_contentionFactor;
}
}
if (s_logger.isLoggable(Level.FINE))
s_logger.log( Level.FINE, name + ": finished." );
}
}
private Runnable getNext( int idx )
{
idx = (idx * FS_PADDING) + FS_PADDING - 1;
for (;;)
{
final Runnable runnable = m_hra.get( idx );
if (runnable == null)
return null;
/* Schmidt D. algorithm suitable for the garbage collector
* environment can not be used here because the same Runnable
* can be scheduled multiple times (to avoid useless object allocation).
*/
if (runnable == LOCK)
continue;
if (m_hra.compareAndSet(idx, runnable, LOCK))
{
if (runnable.nextThreadPoolRunnable == null)
{
m_hra.set( idx, null );
if (m_tra.compareAndSet(idx, runnable, null))
return runnable;
while (runnable.nextThreadPoolRunnable == null);
}
m_hra.set( idx, runnable.nextThreadPoolRunnable );
s_nextUpdater.lazySet( runnable, null );
return runnable;
}
}
}
private static class DummyRunnable extends Runnable
{
public void runInThreadPool()
{
/* Should never be called */
assert( false );
}
}
private static final AtomicReferenceFieldUpdater s_nextUpdater
= AtomicReferenceFieldUpdater.newUpdater( Runnable.class, Runnable.class, "nextThreadPoolRunnable" );
private static final Logger s_logger = Logger.getLogger( ThreadPool.class.getName() );
private static final Runnable LOCK = new DummyRunnable();
private static final int FS_PADDING = 16;
private final String m_name;
private final int m_contentionFactor;
private final Thread [] m_thread;
private final Sync m_sync;
private final AtomicReferenceArray m_hra;
private final AtomicReferenceArray m_tra;
private volatile boolean m_run;
public ThreadPool( String name, int threads, int contentionFactor )
{
m_name = name;
assert( contentionFactor >= 1 );
if (contentionFactor < 1)
contentionFactor = 1;
m_contentionFactor = contentionFactor;
m_thread = new Thread[threads];
for (int idx=0; idx( contentionFactor * FS_PADDING );
m_tra = new AtomicReferenceArray( contentionFactor * FS_PADDING );
m_run = true;
}
public ThreadPool( String name, int threads )
{
this( name, threads, 4 );
}
public final void start()
{
for (Thread thread : m_thread)
thread.start();
}
public final void stopAndWait() throws InterruptedException
{
assert( m_thread != null );
m_run = false;
m_sync.releaseShared( m_thread.length );
for (int idx=0; idx
© 2015 - 2024 Weber Informatics LLC | Privacy Policy