JAVA线程池中阻塞队列

目录

有限队列

SynchronousQueue

SynchronousQueue 队列构造函数

SynchronousQueue 队列使用示例

 ArrayBlockingQueue

ArrayBlockingQueue 队列构造函数

ArrayBlockingQueue 队列使用示例

无限队列

LinkedBlockingQueue

LinkedBlockingQueue 队列构造函数

LinkedBlockingQueue 队列使用示例

PriorityBlockingQueue

PriorityBlockingQueue 队列构造函数

 PriorityBlockingQueue 队列使用


在使用ThreadPoolExecutor线程池的时候,需要指定一个实现了BlockingQueue接口的任务等待队列,用于临时存储提交的任务。

有限队列

SynchronousQueue

SynchronousQueue 是一个不存储元素的阻塞队列。它每个插入操作必须等待另一个线程调用移除操作,否则插入操作将一直处于阻塞状态

在 ThreadPoolExecutor 中使用 SynchronousQueue 作为任务队列时,会有以下特点:

  1. 无存储‌:由于 SynchronousQueue 不存储任务,因此它非常适合于需要立即执行任务的场景。每个提交给线程池的任务都必须立即由一个空闲的线程来执行,否则提交操作将会阻塞。
  2. 高吞吐量‌:在没有任务积压的情况下,SynchronousQueue 可以提供非常高的吞吐量,因为任务是直接传递给执行它们的线程的。
  3. 必须配置足够的线程‌:由于队列不存储任务,如果提交任务的速度超过了线程池处理任务的速度,并且没有足够的线程来立即执行这些任务,那么提交操作将会阻塞。因此,需要确保线程池有足够的线程来处理提交的任务。
  4. 任务拒绝策略‌:如果线程池已经达到了它的最大线程数,并且所有的线程都在忙碌中,那么新提交的任务将会被拒绝。需要为线程池配置一个合适的任务拒绝策略来处理这种情况

SynchronousQueue 队列构造函数

    /**
     * Creates a {@code SynchronousQueue} with nonfair access policy.
     */
    public SynchronousQueue() {
        this(false);
    }

    /**
     * Creates a {@code SynchronousQueue} with the specified fairness policy.
     *
     * @param fair if true, waiting threads contend in FIFO order for
     *        access; otherwise the order is unspecified.
     */
    public SynchronousQueue(boolean fair) {
        transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
    }

SynchronousQueue 队列使用示例

import java.util.concurrent.*;

public class ThreadPoolExecutorExample {
    public static void main(String[] args) {
        // 创建一个 SynchronousQueue 实例
        SynchronousQueue<Runnable> synchronousQueue = new SynchronousQueue<>();

        // 创建一个 ThreadPoolExecutor 实例,使用 SynchronousQueue 作为任务队列
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                4, // 核心线程数
                4, // 最大线程数
                0L, // 线程空闲时间
                TimeUnit.MILLISECONDS,
                synchronousQueue, // 任务队列
                new ThreadPoolExecutor.AbortPolicy() // 任务拒绝策略:直接抛出异常
        );

        // 提交任务给线程池执行
        for (int i = 0; i < 10; i++) {
            executor.execute(() -> {
                System.out.println(Thread.currentThread().getName() + " is executing task.");
            });
        }
    }
}

 ArrayBlockingQueue

‌ArrayBlockingQueue 是一个可选有界队列,默认情况下是无界的(但可以在构造函数中指定容量)。该队列按照先进先出(FIFO)的原则对元素进行排序,新的任务加入到队列尾部,队列获取操作是从队列头部获取任务。

这个队列有固定大小,一旦创建了这样的缓存区,就不能再增加容量。试图向已经满的队列增加任务,会导致操作受到阻塞。同样的,试图从空的队列中获取任务也会受到阻塞。

ArrayBlockingQueue 队列构造函数

    /**
     * Creates a {@code LinkedBlockingQueue} with a capacity of
     * {@link Integer#MAX_VALUE}.
     */
    public LinkedBlockingQueue() {
        this(Integer.MAX_VALUE);
    }

    /**
     * Creates a {@code LinkedBlockingQueue} with the given (fixed) capacity.
     *
     * @param capacity the capacity of this queue
     * @throws IllegalArgumentException if {@code capacity} is not greater
     *         than zero
     */
    public LinkedBlockingQueue(int capacity) {
        if (capacity <= 0) throw new IllegalArgumentException();
        this.capacity = capacity;
        last = head = new Node<E>(null);
    }

    /**
     * Creates a {@code LinkedBlockingQueue} with a capacity of
     * {@link Integer#MAX_VALUE}, initially containing the elements of the
     * given collection,
     * added in traversal order of the collection's iterator.
     *
     * @param c the collection of elements to initially contain
     * @throws NullPointerException if the specified collection or any
     *         of its elements are null
     */
    public LinkedBlockingQueue(Collection<? extends E> c) {
        this(Integer.MAX_VALUE);
        final ReentrantLock putLock = this.putLock;
        putLock.lock(); // Never contended, but necessary for visibility
        try {
            int n = 0;
            for (E e : c) {
                if (e == null)
                    throw new NullPointerException();
                if (n == capacity)
                    throw new IllegalStateException("Queue full");
                enqueue(new Node<E>(e));
                ++n;
            }
            count.set(n);
        } finally {
            putLock.unlock();
        }
    }

ArrayBlockingQueue 队列使用示例

package com.huawei.apig.sdk.demo;
import java.util.concurrent.*;


public class ThreadPoolExecutorExample {
    public static void main(String[] args) {
        // 创建一个使用SynchronousQueue的线程池,并指定AbortPolicy作为拒绝策略
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2,
                2,
                0,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(20), // 创建一个容量为10的队列
                new ThreadPoolExecutor.AbortPolicy());

        // 提交任务给线程池
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executor.execute(() -> {
                System.out.println("Thread " + Thread.currentThread().getName() + " is executing task " + taskId);
                try {
                    // 模拟任务执行时间
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }
        // 关闭线程池
        executor.shutdown();
        try {
            // 等待所有任务完成
            executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        System.out.println("All tasks completed.");
    }
}

无限队列

LinkedBlockingQueue

LinkedBlockingQueue 由链表实现,队列可以指定队列的大小,也可以不指定大小。队列在接收任务的时候,会检测当前线程的数量,如果线程数小于配置的核心线程数,则创建线程处理任务;如果线程数等于配置的核心线程数,则任务存入队列中等待处理。

由此在使用 LinkedBlockingQueue 队列作为线程池队列时,maximumPoolSize 参数的设置是没有意义的,线程池中的最大线程数量就是 corePoolSize 参数值

LinkedBlockingQueue 队列构造函数

创建 LinkedBlockingQueue 队列的三种情况

1. 创建无限队列,默认队列的大小是 Integer.MAX_VALUE

2. 创建指定大小的队列,初始化头结点

3. 创建无限队列,默认队列的大小是 Integer.MAX_VALUE,并且进行队列初始化,入参是需要初始化的元素

    /**
     * Creates a {@code LinkedBlockingQueue} with a capacity of
     * {@link Integer#MAX_VALUE}.
     */
    public LinkedBlockingQueue() {
        this(Integer.MAX_VALUE);
    }

    /**
     * Creates a {@code LinkedBlockingQueue} with the given (fixed) capacity.
     *
     * @param capacity the capacity of this queue
     * @throws IllegalArgumentException if {@code capacity} is not greater
     *         than zero
     */
    public LinkedBlockingQueue(int capacity) {
        if (capacity <= 0) throw new IllegalArgumentException();
        this.capacity = capacity;
        last = head = new Node<E>(null);
    }

    /**
     * Creates a {@code LinkedBlockingQueue} with a capacity of
     * {@link Integer#MAX_VALUE}, initially containing the elements of the
     * given collection,
     * added in traversal order of the collection's iterator.
     *
     * @param c the collection of elements to initially contain
     * @throws NullPointerException if the specified collection or any
     *         of its elements are null
     */
    public LinkedBlockingQueue(Collection<? extends E> c) {
        this(Integer.MAX_VALUE);
        final ReentrantLock putLock = this.putLock;
        putLock.lock(); // Never contended, but necessary for visibility
        try {
            int n = 0;
            for (E e : c) {
                if (e == null)
                    throw new NullPointerException();
                if (n == capacity)
                    throw new IllegalStateException("Queue full");
                enqueue(new Node<E>(e));
                ++n;
            }
            count.set(n);
        } finally {
            putLock.unlock();
        }
    }

LinkedBlockingQueue 队列使用示例

线程池中使用 LinkedBlockingQueue 队列,maxPoolSize 设置失效,设置成跟 corePoolSize 同样大小就好了;拒绝策略理论上也不会触发。

public class LinkedBlockingQueueExample {
    @PostConstruct
    public void init() {
//        线程池中使用 LinkedBlockingQueue 队列
        ThreadFactory namedFactory = new ThreadFactoryBuilder().setNameFormat(
                "threadListTestUseLinkedBlockingQueue").build();
        ExecutorService executorService = new ThreadPoolExecutor(10,
                10,
                1,
                TimeUnit.MINUTES,
                new LinkedBlockingQueue<>(),
                namedFactory,
                new ThreadPoolExecutor.CallerRunsPolicy());
    }
}

PriorityBlockingQueue

在Java中,PriorityBlockingQueue 是一个支持优先级排序的无界阻塞队列,它可以用于线程池中,以便按照任务的优先级来调度执行。虽然Java的标准线程池(如Executors工厂类创建的线程池)通常不直接使用PriorityBlockingQueue,但可以通过自定义线程池的方式来实现这一功能。

PriorityBlockingQueue 队列构造函数

    /**
     * Creates a {@code PriorityBlockingQueue} with the default
     * initial capacity (11) that orders its elements according to
     * their {@linkplain Comparable natural ordering}.
     */
    public PriorityBlockingQueue() {
        this(DEFAULT_INITIAL_CAPACITY, null);
    }

    /**
     * Creates a {@code PriorityBlockingQueue} with the specified
     * initial capacity that orders its elements according to their
     * {@linkplain Comparable natural ordering}.
     *
     * @param initialCapacity the initial capacity for this priority queue
     * @throws IllegalArgumentException if {@code initialCapacity} is less
     *         than 1
     */
    public PriorityBlockingQueue(int initialCapacity) {
        this(initialCapacity, null);
    }

    /**
     * Creates a {@code PriorityBlockingQueue} with the specified initial
     * capacity that orders its elements according to the specified
     * comparator.
     *
     * @param initialCapacity the initial capacity for this priority queue
     * @param  comparator the comparator that will be used to order this
     *         priority queue.  If {@code null}, the {@linkplain Comparable
     *         natural ordering} of the elements will be used.
     * @throws IllegalArgumentException if {@code initialCapacity} is less
     *         than 1
     */
    public PriorityBlockingQueue(int initialCapacity,
                                 Comparator<? super E> comparator) {
        if (initialCapacity < 1)
            throw new IllegalArgumentException();
        this.lock = new ReentrantLock();
        this.notEmpty = lock.newCondition();
        this.comparator = comparator;
        this.queue = new Object[initialCapacity];
    }

    /**
     * Creates a {@code PriorityBlockingQueue} containing the elements
     * in the specified collection.  If the specified collection is a
     * {@link SortedSet} or a {@link PriorityQueue}, this
     * priority queue will be ordered according to the same ordering.
     * Otherwise, this priority queue will be ordered according to the
     * {@linkplain Comparable natural ordering} of its elements.
     *
     * @param  c the collection whose elements are to be placed
     *         into this priority queue
     * @throws ClassCastException if elements of the specified collection
     *         cannot be compared to one another according to the priority
     *         queue's ordering
     * @throws NullPointerException if the specified collection or any
     *         of its elements are null
     */
    public PriorityBlockingQueue(Collection<? extends E> c) {
        this.lock = new ReentrantLock();
        this.notEmpty = lock.newCondition();
        boolean heapify = true; // true if not known to be in heap order
        boolean screen = true;  // true if must screen for nulls
        if (c instanceof SortedSet<?>) {
            SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
            this.comparator = (Comparator<? super E>) ss.comparator();
            heapify = false;
        }
        else if (c instanceof PriorityBlockingQueue<?>) {
            PriorityBlockingQueue<? extends E> pq =
                (PriorityBlockingQueue<? extends E>) c;
            this.comparator = (Comparator<? super E>) pq.comparator();
            screen = false;
            if (pq.getClass() == PriorityBlockingQueue.class) // exact match
                heapify = false;
        }
        Object[] a = c.toArray();
        int n = a.length;
        // If c.toArray incorrectly doesn't return Object[], copy it.
        if (a.getClass() != Object[].class)
            a = Arrays.copyOf(a, n, Object[].class);
        if (screen && (n == 1 || this.comparator != null)) {
            for (int i = 0; i < n; ++i)
                if (a[i] == null)
                    throw new NullPointerException();
        }
        this.queue = a;
        this.size = n;
        if (heapify)
            heapify();
    }

 PriorityBlockingQueue 队列使用

要使用 PriorityBlockingQueue 在线程池中管理任务,需要实现以下几步

1. 定义一个实现RunnableCallable接口的任务类‌,并且这个类需要实现Comparable接口,以便在队列中根据优先级进行排序

2. 创建一个PriorityBlockingQueue实例‌,并将其作为任务队列传递给自定义的线程池

3. 实现一个自定义的线程池类‌,或者使用ThreadPoolExecutor类,并将 PriorityBlockingQueue 作为任务队列传递给它


import java.util.concurrent.*;

// 定义一个实现Runnable接口的任务类,并实现Comparable接口
class PriorityTask implements Runnable, Comparable<PriorityTask> {
    private final int priority;
    private final String taskName;

    public PriorityTask(int priority, String taskName) {
        this.priority = priority;
        this.taskName = taskName;
    }

    @Override
    public void run() {
        System.out.println("Executing task: " + taskName + " with priority: " + priority);
    }

    @Override
    public int compareTo(PriorityTask other) {
        // 任务优先级比较,优先级大的排在前面
        return Integer.compare(other.priority, this.priority);
    }
}

public class ThreadPoolExecutorExample {
    public static void main(String[] args) {
        // 创建一个PriorityBlockingQueue实例
        PriorityBlockingQueue<Runnable> priorityQueue = new PriorityBlockingQueue<>();
        ThreadPoolExecutor executorService = new ThreadPoolExecutor(1,
                1,
                1,
                TimeUnit.MINUTES,
                priorityQueue);

        for (int i = 0; i < 10; i++) {
            int priority = (int) (Math.random() * 10); // 随机生成优先级
            System.out.println("random priority: " + priority);
            executorService.execute(new PriorityTask(priority, "Task-" + i));
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值