4

I have used a semaphore to restrict the number of threads accessing a function. I want the thread to be awakened next should be chosen by some priority which i will be giving,not by default way that semaphore awaken's them ? How can we achieve this ?

Here is the implementation :

class MyMathUtil2 implements Runnable {
    double a;
    double b;
    String name = "demo";
    Thread t;
    //static int currentCount = 0;
    static int MAX_COUNT = 2;

    private final Semaphore available = new Semaphore(MAX_COUNT, true);

    MyMathUtil2(double v1, double v2) {
        a = v1;
        b = v2;
        t = new Thread(this, name);
        System.out.println("New thread: " + t);
        t.start();
    }

    public void InternalPow(double a, double b) throws InterruptedException {
        available.acquire();
        try {
            System.out.println("Power of " + a + " and " + b + " : " + Math.pow(a, b));
        } finally {
            available.release();
        }

    }

    public void run() {
        try {
            InternalPow(a, b);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

class TestMyMathUtil2 {
    public static void main(String args[]) {
        new MyMathUtil2(10.2, 8);
        new MyMathUtil2(11, 56);
        new MyMathUtil2(10.2, 9);
        new MyMathUtil2(2, 3);
        new MyMathUtil2(4, 5);
    }
}
xingbin
  • 27,410
  • 9
  • 53
  • 103
ritesh
  • 45
  • 7
  • The fairness parameter (true above) ensures that threads are awakened in order of arrival, but as far as I know there is no built-in class that can awaken threads in priority order. You would have to subclass Semaphore or use other more basic primitives and do that yourself. Check the source for Semaphore, as it does support order it should be fairly close to what you need. – ewramner May 02 '18 at 07:15
  • don't you want to use a bounded `PriorityBlockingQueue`? – Andrew Tobilko May 02 '18 at 07:26
  • @Andrew ..i don't have any experience on working with PriorityBlockingQueue. If u have used it before,please change the code accordingly and share with us...that wud b really helpful. – ritesh May 02 '18 at 09:19
  • Can you take a step back and make us understand _why_ you want to do this. Why do you need to have this priority order. Right now you are asking about specifics of the implementation. – Gray May 02 '18 at 16:21
  • Hi @Gray ,glad u asked..it's actually a part of an interview question asked to me by a reputed networking company. and if you think more on this..u will realise that it does make sense because everytime it might nt be a/c to FCFS rule. what if u have n number of sms threads waiting in threadPool and they have types,u will definately want the OTP containing smses to be served before the normal smses. – ritesh May 02 '18 at 17:01

1 Answers1

3

Well, a Semaphore does not support priority.

I suggest to use a ThreadPoolExecutor with 2 fixed threads and a PriorityBlockingQueue to solve this problem.

A ThreadPoolExecutor with 2 fixed threads can make sure that at any moment, there is at most 2 task running. The other tasks will be put in this PriorityBlockingQueue, and the thread pool will retrieve tasks from the queue based on a custom Comparator.

Here is an example. Every Runnable in this example is supposed to print a number. It submits the Runnables in reverse order: 1000, 999, ..., 1. But the Runnable will be executed in nature order: 1, 2, ...., 1000 using a priority queue.

import java.util.Comparator;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

class ComparableRunnable implements Runnable {

    public int index;

    ComparableRunnable(int index) {
        this.index = index;
    }

    public void run() {
        System.out.println(Thread.currentThread().getName() + "-index : " + index);
        try {
            // sleep current thread, so the other thread can print
            // this is not mandatory, without this, the result might not follow strict natural order
            // for example, thread1 print 1, 
            // thread2 take 2 but did not print it immediatly, 
            // thread1 print 3, 
            // thread2 print 2
            // the result will be 1, 3, 2,
            Thread.sleep(10);
        } catch (Exception e) {

        }
    }

    public static void main(String[] args) {
        int corePoolSize = 2; // fixed thread number
        long ignore = 0L;

        // comparator
        Comparator<Runnable> comparator = new Comparator<Runnable>() {
            @Override
            public int compare(Runnable o1, Runnable o2) {
                int index1 = ((ComparableRunnable)o1).index;
                int index2 = ((ComparableRunnable)o2).index;
                // you should implement this method based on your own order
                return Integer.compare(index1, index2);
            }
        };

        // use the comparator create a priority queue
        PriorityBlockingQueue<Runnable> queue = new PriorityBlockingQueue<>(10, comparator);

        ThreadPoolExecutor executor =
                new ThreadPoolExecutor(corePoolSize, corePoolSize, ignore, TimeUnit.SECONDS, queue);

        // Warm the thread pool up
        // this is not mandatory, without this, it will print 1000, 999, 1, 2, ...., 998
        // because the first two Runnbale will be executed once they are submitted
        for (int i = 0; i < corePoolSize; i++) {
            executor.execute(() -> {
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {

                }
            });
        }

        // submit in 1000, 999, ..., 1 order
        // print in 1, 2, 3, ..., 1000 order
        for (int i = 1000; i > 0; i--) {
            executor.execute(new ComparableRunnable(i));
        }
    }
}

Result:

pool-1-thread-1-index : 1
pool-1-thread-2-index : 2
pool-1-thread-1-index : 3
pool-1-thread-2-index : 4
pool-1-thread-2-index : 5
...
pool-1-thread-2-index : 996
pool-1-thread-2-index : 997
pool-1-thread-1-index : 998
pool-1-thread-2-index : 999
pool-1-thread-1-index : 1000
xingbin
  • 27,410
  • 9
  • 53
  • 103