<bdo id="4g88a"><xmp id="4g88a">
  • <legend id="4g88a"><code id="4g88a"></code></legend>
    Fork me on GitHub

    小米面試:如何實現優先級線程池?

    我們知道,線程池中的所有線程都是由統一的線程工廠來創建的,當我們指定線程工廠時,線程池中的所有線程會使用我們指定的線程工廠來創建線程;但如果沒有指定線程工廠,則會使用默認的線程工廠 DefaultThreadFactory 來創建線程,核心源碼如下:

    DefaultThreadFactory() {
        @SuppressWarnings("removal")
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() :
                              Thread.currentThread().getThreadGroup();
        namePrefix = "pool-" +
                      poolNumber.getAndIncrement() +
                     "-thread-";
    }
    

    那么問題來了,面試官問的是“如何實現優先級線程池?”,為什么我們一上來先講了線程工廠呢?

    這是因為,當我們講到線程池優先級的時候,我們首先會想到線程的優先級,所以按照慣性思考,當面試官問到如何使用實現優先級線程池時,我們首先會考慮是不是在創建線程池的時候,可以通過某種方法來創建不同的線程優先級,從而實現優先級線程池?這就是開頭我們一上來就講線程工廠的原因。

    那在線程工廠中如何設置線程的優先級呢?

    它的設置也比較簡單,如下代碼所示:

    import java.util.concurrent.ThreadFactory;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    public class CustomThreadPoolExecutorDemo {
        public static void main(String[] args) {
            // 自定義線程工廠
            ThreadFactory threadFactory = new CustomThreadFactory();
            // 創建線程池
            ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 2, 0, 
                                                                 TimeUnit.MILLISECONDS, 
                                                                 new LinkedBlockingQueue<>(), 
                                                                 threadFactory);
            // 提交任務
            executor.execute(() -> System.out.println("Task 1"));
            executor.execute(() -> System.out.println("Task 2"));
            // 關閉線程池
            executor.shutdown();
        }
    
        static class CustomThreadFactory implements ThreadFactory {
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                // 設置線程優先級為最低優先級
                thread.setPriority(Thread.MIN_PRIORITY); 
                return thread;
            }
        }
    }
    

    但是這種方式也有問題,那就是線程工廠是統一的,所以即使能在線程工廠中設置線程的優先級,那么也是將整個線程池中的所有線程都設置成統一的優先級了,而不能解決咱們本文提出的問題的,那如何才能實現優先級線程池呢?

    1.優先級線程池實現思路

    轉念一想,既然不能在線程優先級上下功夫,但我們是否可以在線程池的任務隊列上動點心思呢?

    此時我們想到,可以使用 PriorityBlockingQueue 優先級隊列來對任務進行排序?。≒riorityBlockingQueue 天生支持按照優先級自動排序任務的),這樣不就能保證優先級高的任務會被線程池優先獲取并執行了嘛!

    所以,有時候一條路走不通的時候,我們可以嘗試換一個思路再試試。

    2.優先級隊列使用

    我們先來測試一下 PriorityBlockingQueue 的使用,以嘗試其可行性,示例代碼如下:

    import java.util.concurrent.PriorityBlockingQueue;
    
    public class PriorityBlockingQueueExample {
        public static void main(String[] args) {
            PriorityBlockingQueue<Task> priorityQueue = new PriorityBlockingQueue<>();
    
            // 添加任務到優先級隊列
            priorityQueue.add(new Task("Task 1", 1));
            priorityQueue.add(new Task("Task 4", 4));
            priorityQueue.add(new Task("Task 3", 3));
            priorityQueue.add(new Task("Task 2", 2));
    
            // 從優先級隊列中取出任務并執行
            while (!priorityQueue.isEmpty()) {
                Task task = priorityQueue.poll();
                if (task != null) {
                    task.execute();
                }
            }
        }
    
        static class Task implements Comparable<Task> {
            private String name;
            private int priority;
    
            public Task(String name, int priority) {
                this.name = name;
                this.priority = priority;
            }
    
            public void execute() {
                System.out.println("Executing task: " + name);
            }
    
            @Override
            public int compareTo(Task o) {
                return Integer.compare(this.priority, o.priority);
            }
        }
    }
    

    以上程序的執行結果如下:
    image.png
    從上述結果和代碼可以看出,我們添加任務的順序是:1、4、3、2,但最終會按照優先級排隊執行的順序是:1、2、3、4,執行結果符合我們的預期,優先級高的任務先被執行了(數字越小,優先級越高)。

    3.優先級線程池

    因此,我們實現的優先級線程池的最終代碼如下:

    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.PriorityBlockingQueue;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    public class PriorityThreadPool {
        public static void main(String[] args) {
            BlockingQueue<Runnable> queue = new PriorityBlockingQueue<>(1000);
    
            ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1,
                    0, TimeUnit.SECONDS, queue
            );
    
            for (int i = 0; i < 100; i++) {
                int finalI = i;
                executor.execute(new PriorityTask(i, () -> {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.println("優先級:" + finalI);
                }));
            }
        }
    
        static class PriorityTask implements Runnable, Comparable<PriorityTask> {
            private final int priority;
            private final Runnable task;
    
            public PriorityTask(int priority, Runnable task) {
                this.priority = priority;
                this.task = task;
            }
    
            @Override
            public void run() {
                task.run();
            }
    
            @Override
            public int compareTo(PriorityTask other) {
                // 優先級高的任務應該排在前面(數字越小優先級越大)
                return Integer.compare(this.priority, other.priority);
            }
        }
    }
    

    以上程序執行結果如下:
    image.png
    從上述結果可以看出,線程池是完全按照優先級從高到低的順序執行的(數字越小優先級越高),如果將 compareTo 中的排序方法倒置之后,那么線程池的執行順序就完全相反了,可見使用 PriorityBlockingQueue 實現優先級線程池的效果非常顯著。

    課后思考

    那么問題來了,PriorityBlockingQueue 在并發環境下會有線程安全問題嗎?PriorityBlockingQueue 底層是如何保證線程安全的?

    本文已收錄到我的面試小站 www.javacn.site,其中包含的內容有:Redis、JVM、并發、并發、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、設計模式、消息隊列等模塊。

    posted @ 2024-05-20 16:19  磊哥|www.javacn.site  閱讀(194)  評論(0編輯  收藏  舉報
    免费视频精品一区二区_日韩一区二区三区精品_aaa在线观看免费完整版_世界一级真人片
    <bdo id="4g88a"><xmp id="4g88a">
  • <legend id="4g88a"><code id="4g88a"></code></legend>