-1

Problem: I have to manage a post office with two queue, one is managed by the programmer(the first queue), the other is implicit in the ThreadPool. So, each thread has to pass in the first queue, then in the second, then should be executed. I have a solution, but the problem is that threads are executed only after all of them are inserted in the first queue. I think it is logically right to have a little few thread in the queue, and others which are executed meanwhile. This is the (wrong) solution find by me. Tasks are modelled with class Task which implements Runnable. The thradPool is nother class called UfficioPostale, then there is First with 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();
}
}

Cutted output is this. Threads starts to 1 from 50, all terminate

Cutted output is this. Threads starts to 1 from 50, all

Dylan Nico
  • 39
  • 8

1 Answers1

0

I don't see anything logically wrong with your code. I guess only reason you are not seeing tasks getting executed before all of them are inserted in first queue is because your main thread ( executing while loop) is not releasing CPU and allowing task threads to get executed. I think, If you put a small sleep ( 1ms sleep to just main thread release the CPU ) you will see other threads getting executed before all the tasks are inserted in queue 1.

One better way to write this code is to not have this p.sizeq()<10 check in code below

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());

but replace it by

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());

key difference is that since ThreadPoolExecutor is initialzed with a blocking queue of size 10 , it will not accept more than 10 tasks and block the operation "p.executeTask(q1.take())" until queue size is less than 10. I believe this is what you are trying to achieve by doing a size check, so basically size check is redundant.

This will also give you expected execution of tasks before all the threads are inserted in queue 1 without adding sleep statement inside while ( as suggested above ) loop because, while loop will be blocked ( thus thread will go in waiting state and release the CPU ) until some of the tasks are executed to reduced the queue 2 size to < 10.

Vishal
  • 635
  • 4
  • 9