java中的ThreadPool有两个队列

Posted

技术标签:

【中文标题】java中的ThreadPool有两个队列【英文标题】:ThreadPool in java with two queue 【发布时间】:2021-11-19 23:01:22 【问题描述】:

问题:我必须管理一个有两个队列的邮局,一个由程序员管理(第一个队列),另一个隐含在 ThreadPool 中。所以,每个线程都必须在第一个队列中传递,然后在第二个队列中,然后应该被执行。我有一个解决方案,但问题是线程只有在所有线程都插入第一个队列后才会执行。我认为在队列中有几个线程,同时执行其他线程在逻辑上是正确的。这是我找到的(错误的)解决方案。任务使用实现 Runnable 的类 Task 建模。 thradPool 是另一个名为 UfficioPostale 的类,然后是 First 和 main。

import java.util.concurrent.*;
import java.lang.*;
import java.util.*;

class Task implements Runnable

public int id;

public Task(int id)
    this.id=id;


public void run()
    int delay = ThreadLocalRandom.current().nextInt(0, 50 + 1);
    try 
        Thread.sleep(delay);
        System.out.printf("Persona %d: eseguita\n",this.id);
      
    catch (InterruptedException e) 
        System.err.println("Interruzione su sleep.");
    
    System.out.printf("Persona %d: uscita da sportello\n", this.id);

    


class UfficioPostale

private ThreadPoolExecutor pool;
private ArrayBlockingQueue<Runnable> q;

//TODO:controllo su parametri funzioni
public UfficioPostale(int numSportelli,int dimq)
    q = new ArrayBlockingQueue<Runnable>(dimq);
    pool = new ThreadPoolExecutor(numSportelli,numSportelli,60L,TimeUnit.MILLISECONDS,q);


public void executeTask(Task t)
    //TODO: controlli su parametri
    pool.execute(t);

public int sizeq()
    return q.size();

public void close()
    pool.shutdown();



public class First
public static void main(String[] args)
    
    int numSportelli = 4; //number of core
    int dimq = 10; //dim second queue(the one in threadPool)
    int k = 50; //dim first queue
    LinkedBlockingQueue<Task> q1 = new LinkedBlockingQueue<Task>(k); //prima coda esterna
UfficioPostale p = new UfficioPostale(numSportelli, dimq);
    //Assumo che la dimensione della coda esterna sia maggiore della dimensione della coda interna
    int numThread = 50;
    int i = 1;
    while(numThread >= 0)
        Task t = new Task(i);
        try
            q1.put(t);
            System.out.println("Task "+i+" inserted in queue 1");
        catch(Exception e)
            System.out.println("queue 1 full");
        
        //se la seconda coda ha spazio e se la prima non e' vuota, allora mando il thread alla seconda coda, pii' vicina allo sportello
        if(p.sizeq()<10  && q1.isEmpty() == false)
            
            try
                //prendo l'elemento dalla coda esterna e lo eseguo, permettendo al pool di gestire la coda interna come opportuno
                p.executeTask(q1.take());
    catch (Exception e) 
        System.out.println("full queue");
    
        
        numThread--;
        i++;
    
    //Se ci sono ancora task in attesa nella prima coda, li trasfrisco nella seconda
    while(q1.isEmpty() == false) 
        if (p.sizeq()<10) 
    try 
                p.executeTask(q1.take());
     catch (InterruptedException e) 
                e.printStackTrace();
               
        

    //chiudo il pool
    p.close();


截断输出是这个。线程从 50 开始到 1,全部终止

【问题讨论】:

【参考方案1】:

我认为您的代码在逻辑上没有任何问题。我想您在所有任务都插入第一个队列之前没有看到任务被执行的唯一原因是因为您的主线程(执行 while 循环)没有释放 CPU 并允许任务线程被执行。我认为,如果你放一个小睡眠(1ms 睡眠到主线程释放 CPU),你会看到其他线程在所有任务都插入队列 1 之前被执行。

编写此代码的一种更好的方法是不要将 p.sizeq()

if(p.sizeq()<10  && q1.isEmpty() == false)
        try
            //prendo l'elemento dalla coda esterna e lo eseguo, permettendo al pool di gestire la coda interna come opportuno
            p.executeTask(q1.take());

但替换为

if(q1.isEmpty() == false)
            try
                //prendo l'elemento dalla coda esterna e lo eseguo, permettendo al pool di gestire la coda interna come opportuno
                p.executeTask(q1.take());

关键区别在于,由于 ThreadPoolExecutor 使用大小为 10 的阻塞队列进行初始化,它不会接受超过 10 个任务并阻塞操作“p.executeTask(q1.take())”,直到队列大小小于 10 . 我相信这就是你试图通过进行尺寸检查来实现的目标,所以基本上尺寸检查是多余的。

这也将在所有线程插入队列 1 之前为您提供预期的任务执行,而无需在 while(如上所述)循环中添加 sleep 语句,因为 while 循环将被阻塞(因此线程将进入等待状态并释放CPU ) 直到执行某些任务以将队列 2 的大小减小到

【讨论】:

以上是关于java中的ThreadPool有两个队列的主要内容,如果未能解决你的问题,请参考以下文章

通过threadpool初试多线程

Java并发之ThreadPool

我可以使用 boost::threadpool 作为“线程安全队列”吗?

c#线程池中的异常

ThreadPool 是 Executor 就像 Polling 一样?

概述 .NET 6 ThreadPool 实现