我正在尝试使用JAVA线程池,并且想要知道无论如何我都可以在没有提交线程时关闭线程池,并在一个线程完成执行时提交线程。
为了更清楚,我有一个THREAD_LIMIT
变量Integer
类型,这是线程可以执行最大并行和递归算法,它假定在调用自身之前检查活动的线程数。如果活动的线程数小于线程限制,它将向线程池提交一个新线程,否则在同一个线程上调用递归。
我遇到的问题是跟踪活动线程并在没有提交新线程时关闭线程池。我希望使用多线程从代码中获得最大的性能。
我按照this教程创建了自己的线程池并使用了
public int getTaskQueueSize() {
return taskQueue.size();
}
在<{1}}类中以获得活动的线程数。
在主要班级我正在使用
ThreadPool
在主类中关闭Threadpool。但是过了一段时间它就会停止产生新的线程。但是一个线程继续在递归中完成工作。
更新1:已添加代码
所以我发现向线程池提交任务工作正常。但我意外地添加了最近代码更改的错误,这阻止我向线程池提交更多任务并从 void shutdownExecutor() {
while (tp.getTaskQueueSize() != 0) {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(HamiltonPaths.class.getName()).log(Level.SEVERE, null, ex);
}
// System.out.println("Not STopping tp");
}
tp.shutdown();
// System.out.println("Stopped tp");
}
函数关闭线程池,因为shutdownExecutor()
返回了一个或多个任务的初始大小没有从que中删除。
我使用以下逻辑来决定是否提交新任务或继续进行递归。
tp.getTaskQueueSize()
BlockingQueueCustom.java
if ((this.tp.getTaskQueueSize() < threadLimit) && (!this.tp.isPoolShutDownInitiated())) {
spawnNewThread(new PTask(cp, get));//Class that implements the Runnable and do the same thing as the function called in below statement.
} else {
PPath(cp, get);// call to the function
}
LinkedBlockingQueueCustom.java
package threadpool;
abstract interface BlockingQueueCustom<E>
{
public abstract void put(E paramE)
throws InterruptedException;
public abstract E take()
throws InterruptedException;
public abstract int size();
}
ThreadPool.java
package threadpool;
import java.util.LinkedList;
import java.util.List;
class LinkedBlockingQueueCustom<E>
implements BlockingQueueCustom<E> {
private List<E> queue;
private int maxSize;
public LinkedBlockingQueueCustom(int maxSize) {
this.maxSize = maxSize;
this.queue = new LinkedList();
}
public synchronized void put(E item)
throws InterruptedException {
if (this.queue.size() == this.maxSize) {
wait();
}
this.queue.add(item);
notifyAll();
}
public synchronized E take()
throws InterruptedException {
if (this.queue.isEmpty()) {
wait();
}
notifyAll();
if (this.queue.isEmpty()) {
return null;
}
return (E) this.queue.remove(0);
}
public synchronized int size() {
return this.queue.size();
}
}
ThreadPoolsThread.java
package threadpool;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ThreadPool {
private BlockingQueueCustom<Runnable> taskQueue;
int size = 0;
int taskExecuted = 0;
ThreadPoolsThread[] threadPoolsThread;
public int getTaskExecuted() {
return this.taskExecuted;
}
public synchronized void dectaskExec() {
this.taskExecuted -= 1;
}
public int getSize() {
return this.size;
}
public BlockingQueueCustom<Runnable> getTaskQueue() {
return this.taskQueue;
}
public int getTaskQueueSize() {
return this.taskQueue.size();
}
private boolean poolShutDownInitiated = false;
public ThreadPool(int nThreads) {
this.taskQueue = new LinkedBlockingQueueCustom(nThreads);
this.size = nThreads;
this.threadPoolsThread = new ThreadPoolsThread[nThreads + 1];
for (int i = 1; i <= nThreads; i++) {
this.threadPoolsThread[i] = new ThreadPoolsThread(this.taskQueue, this);
this.threadPoolsThread[i].setName("" + i);
this.threadPoolsThread[i].start();
}
}
public synchronized void execute(Runnable task) {
if (this.poolShutDownInitiated) {
try {
throw new Exception("ThreadPool has been shutDown, no further tasks can be added");
} catch (Exception ex) {
Logger.getLogger(ThreadPool.class.getName()).log(Level.SEVERE, null, ex);
}
}
this.taskExecuted += 1;
try {
this.taskQueue.put(task);
} catch (InterruptedException ex) {
Logger.getLogger(ThreadPool.class.getName()).log(Level.SEVERE, null, ex);
}
}
public boolean isPoolShutDownInitiated() {
return this.poolShutDownInitiated;
}
public synchronized void shutdown() {
this.poolShutDownInitiated = true;
}
}
答案 0 :(得分:1)
似乎存在根本性的误解。您没有“向线程池提交新线程”,您将 tasks 提交给执行程序服务(可能实现为线程池)。执行程序服务管理线程并决定是启动,停止还是重用它们。如果将执行程序配置为具有最大线程数,则它将使用不超过指定的数字。如果您提交的任务多于可用线程,则这些任务将排队。因此,队列的大小不是线程数。
通常,您不应该实现自己的线程池,尤其是当您还没有完全理解它们的作用时。 Java已经内置了十多年的实现。您可以使用Executors.newFixedThreadPool(threadCount)
使用指定数量的线程来获取线程池执行程序。
如果你想强制执行任务没有入队,而是在所有线程忙的时候总是由调用者执行,那么实现起来并不难。使用the constructor allowing to specify a custom queue and RejectedExecutionHandler
以及ThreadPoolExecutor
和SynchronousQueue
明确创建CallerRunsPolicy
:
ThreadPoolExecutor e=new ThreadPoolExecutor(threadCount, threadCount,
1, TimeUnit.MINUTES, new SynchronousQueue<>(), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
在Java 8之前,您必须使队列类型明确:new SynchronousQueue<Runnable>()
这会将提交的任务传递给空闲线程(如果有),但在提交线程中执行它。请注意,当核心大小和最大大小相同时,如上例所示,超时值无关紧要。
如果您已提交所有任务,则无需额外检查即可调用shutDown()
。在停止所有线程之前,它仍将执行挂起的任务。