在我看来,使用我自己的以下SupervisedExecutor和ExecutorSuperviser实现我的表现不佳,您觉得这段代码中的效率是多少?我想学习如何提高效率。
ExecutorSuperviser类:
public class ExecutorSuperviser {
private SupervisedExecutor[] threadPool;
private int poolSize = 0;
private LinkedList<Runnable> q;\\my own implementation of linkedlist
public ExecutorSuperviser(int nThreads) {
threadPool=new SupervisedExecutor[poolSize=nThreads];
q=new LinkedList<Runnable>();
init();
}
public void execute(Runnable r) {
synchronized (q) {
q.addToTail(r);
}
for (int i=0;i<poolSize;i++)
if (!threadPool[i].isBusy()) {
if (!threadPool[i].isAlive()) threadPool[i].start();
threadPool[i].interrupt();
return;
}
}
private void init() {
for (int i=0;i<poolSize;i++) {
threadPool[i]=new SupervisedExecutor(this);
}
}
public Object getLock() {
return q;
}
public Runnable getTask() {
return q.removeHead();
}
public void terminate() {
for (int i=0;i<poolSize;i++)
threadPool[i].terminate();
}
public void waitUntilFinished() {
while (!isFinished()) {
try {
Thread.sleep(Thread.MAX_PRIORITY);
} catch (InterruptedException e) {}
}
}
private boolean isFinished() {
for (int i=0;i<poolSize;i++)
if (threadPool[i].isBusy()) return false;
return q.isEmpty();
}
}
SupervisedExecutor类:
public class SupervisedExecutor extends Thread {
private boolean terminated = false;
private Boolean busy = false;
private ExecutorSuperviser boss;
SupervisedExecutor (ExecutorSuperviser boss) {
this.boss=boss;
}
public void run() {
while (!terminated) {
try {
sleep(MAX_PRIORITY);
} catch (InterruptedException e) {
synchronized (busy) {
busy=true;
}
Runnable r;
while (true) {
synchronized (boss.getLock()) {
r=boss.getTask();
}
if (r!=null) r.run();
else break;
}
synchronized (busy) {
busy=false;
}
}
}
}
public boolean isBusy() {
boolean isBusy;
synchronized (boss.getLock()) {
isBusy=busy;
}
return isBusy;
}
public void terminate() {
terminated=true;
}
}
答案 0 :(得分:1)
以下具有以下优点的解决方案如何:
作为ThreadPoolExecutor的子类,您无需重新实现ThreadPoolExecutor
为您所做的一切,只是为了获得您所追求的waitUntilFinished()
功能
利用ReentrantLock
,Condition
和await()
/ signal()
,您可以避免忙碌等待,这肯定会影响效果。
此实现的工作原理是利用beforeExecute()
公开的afterExecute()
和ThreadPoolExecutor
方法来保留我们自己的活动任务数。我不使用getActiveCount()
,因为根据JavaDoc,它并不能保证一个确切的答案(尽管可能在ThreadPoolExecutor
的情况下它提供了一个确切的答案,我需要研究进一步确定)。
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class WaitableThreadPoolExecutor extends ThreadPoolExecutor
{
private Condition waitCondition;
private ReentrantLock lock;
private int taskCount = 0;
public WaitableThreadPoolExecutor( int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue )
{
super( corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue );
lock = new ReentrantLock( );
waitCondition = lock.newCondition( );
}
// if isEmpty() is true, then there is no need to block
// otherwise, wait until waitCondition is signaled
public void waitUntilFinished( )
{
lock.lock( );
try
{
while ( !isEmpty( ) )
waitCondition.await( );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
finally
{
lock.unlock( );
}
}
// the ThreadPool is empty if our taskCount is 0 and the
// work queue is empty (this may not be bullet-proof, for one
// thing, I'm hesitant to use getActiveCount() because it
// does not guarantee an exact answer
protected boolean isEmpty( )
{
lock.lock( );
try
{
return taskCount == 0 && getQueue( ).isEmpty( );
}
finally
{
lock.unlock( );
}
}
// increment our task count before executing each task
@Override
protected void beforeExecute( Thread t, Runnable r )
{
super.beforeExecute( t, r );
lock.lock( );
try
{
taskCount += 1;
}
finally
{
lock.unlock( );
}
}
// decrement our task count after executing each task
// then, if the pool is empty, signal anyone waiting
// on the waitCondition
@Override
protected void afterExecute( Runnable r, Throwable t )
{
super.afterExecute( r, t );
lock.lock( );
try
{
taskCount -= 1;
if ( isEmpty( ) ) waitCondition.signalAll( );
}
finally
{
lock.unlock( );
}
}
public static void main( String[] args )
{
WaitableThreadPoolExecutor pool = new WaitableThreadPoolExecutor( 2, 4, 5000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>( ) );
for ( int i = 0 ; i < 10 ; i++ )
{
final int threadId = i;
pool.execute( new Runnable( )
{
@Override
public void run( )
{
try { Thread.sleep( (int) ( Math.random( ) * 5000 ) ); } catch ( InterruptedException e ) { }
System.out.println( threadId + " done." );
}
});
}
pool.waitUntilFinished( );
System.out.println( "Done waiting." );
}
}
我添加了一个简单的main()
方法,您可以将其用作测试用例。它启动了10个线程,这些线程在打印之前等待一段随机的时间。然后主线程调用waitUntilFinished()
。
结果看起来像(最重要的是Done waiting.
将始终打印在最后:
1 done.
2 done.
0 done.
4 done.
3 done.
5 done.
7 done.
8 done.
6 done.
9 done.
Done waiting.
答案 1 :(得分:0)
就个人而言,我发现使用普通的ExecutorService更简单,更容易。
注意:这是您需要的所有代码。
ExecutorService es = Executors.newCachedThreadPool();
List<Future<Void>>futures = new ArrayList<Future<Void>>();
for (int i = 0; i < 10; i++) {
final int threadId = i;
futures.add(es.submit(new Callable<Void>() {
@Override
public Void call() throws InterruptedException {
Thread.sleep((int) (Math.random() * 1000));
System.out.println(threadId + " done.");
return null;
}
}));
}
for (Future<Void> future : futures)
future.get();
System.out.println("Done waiting.");
es.shutdown();
打印
2 done.
4 done.
7 done.
6 done.
8 done.
5 done.
9 done.
1 done.
3 done.
0 done.
Done waiting.