我处理了一个线程应用程序的设计,它具有以下要求:它必须具有基于一天中的时间(高峰/非高峰)运行的动态线程数。

我做了功课并研究了最好的方法,我发现java有一个名为ThreadPoolExecutor的类:java.util.concurrent.ThreadPoolExecutor.ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
这里关注的两个变量是corePoolSize 和maximumPoolSize,它们与workQueue 一起充当线程池的下限和上限。调整这些值有不同的策略,如果不需要显式设置这些参数,建议使用执行器工厂方法而不是构造函数。

public class Main {
    public static void main(String[] args) {
        final BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(100);
        final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(0, 10, 0L, TimeUnit.MILLISECONDS, queue);
        threadPool.setRejectedExecutionHandler(new RejectedExecutionHandler() {
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                try {
                    executor.getQueue().put(r);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                threadPool.setCorePoolSize(1);
                threadPool.setMaximumPoolSize(1);
                System.out.println("changed");
            }
        };
        new Timer().schedule(task, 10000);

        for (int i = 0; i < 400; i++) {
            threadPool.submit(new WorkItem(i));
        }
    }
}

这是类似于要运行的线程的类
public class WorkItem implements Runnable {
    private int workItemNumber;
    private long startTime;

    public WorkItem(int workItemNumber) {
        this.workItemNumber = workItemNumber;
    }

    @Override
    public void run() {
        startTime = System.currentTimeMillis();
        System.out.println("thread Number: " + workItemNumber + " started at: " + startTime);
        while (System.currentTimeMillis() - startTime < 5000) {
        }
        System.out.println("WorkItem done: " + workItemNumber);
    }
}

但是,查看日志,执行的线程数保持不变,没有变化。

最佳答案

您的代码完全按照您的意图运行。 10 个线程启动并运行,100 个线程排队。此时,您的主线程(一个排队线程)被阻塞队列阻塞。然后您的计时器将可用线程更改为 1,这意味着您的队列处理速度更慢。然而,您看到的是,因为您的线程必须等待超过 10 秒才能实际执行它们立即完成。尝试对您的代码进行以下更改:

public class WorkItem implements Runnable {
    private long startTime;
    private long runTime;
    private int workItemNumber;

    public WorkItem(long startTime, int workItemNumber) {
        this.startTime = startTime;
        this.workItemNumber= workItemNumber;
    }

    @Override
    public void run() {
        System.out.println("WorkItem started: " + workItemNumber + " Queued at: " + startTime);
        runTime = System.currentTimeMillis();
        while (System.currentTimeMillis() - runTime < 10000) {
        }
        System.out.println("WorkItem done: " + workItemNumber);
    }
}

这将让您看到如您所愿发生的执行。在核心池设置为 0 的情况下使用数组阻塞队列的奇怪之处在于,它只会启动一个线程,然后填满队列,然后启动更多线程(达到最大池大小)。如果您对排队代码进行细微更改,您就会看到这种情况发生。
for (int i = 1; i < 101; i++) {
    threadPool.submit(new WorkItem(System.currentTimeMillis(), i));
}

for (int i = 101; i < 401; i++) {
    long thisTime = System.currentTimeMillis();
    threadPool.submit(new WorkItem(System.currentTimeMillis(), i));
    while (System.currentTimeMillis() - thisTime < 500) {

    }
}

关于java - ThreadPoolExecutor 没有正确收缩,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28567238/

10-13 03:27