如何优先考虑信号量中的线程?

问题描述:

我使用信号量来限制访问函数的线程数.我希望接下来要唤醒的线程应该由我要赋予的优先级选择,而不是默认情况下信号量唤醒的线程?我们如何实现这一目标?

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 ?

这里是实现:

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

好吧,Semaphore不支持优先级.

我建议使用 具有2固定线程和

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

A ThreadPoolExecutor可以确保在任何时候最多有一个2任务正在运行.其他任务将放置在此PriorityBlockingQueue中,并且线程池将基于自定义的

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.

这里是一个例子.在此示例中,每个Runnable都应打印一个数字.它以相反的顺序提交Runnable:1000、999,...,1. 但是Runnable将使用优先级队列按自然顺序执行:1、2,...,1000.

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

结果:

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