天天看点

BlockingQueue知识合集

作者:四季更新221789896

BlockingQueue常用实现类

Java中的BlockingQueue是一个接口,它定义了一组阻塞队列的操作方法。它的实现类包括:

1. ArrayBlockingQueue:基于数组实现的有界阻塞队列,必须指定队列大小。

2. LinkedBlockingQueue:基于链表实现的可选有界阻塞队列,如果不指定队列大小,则默认大小为Integer.MAX_VALUE。

3. PriorityBlockingQueue:基于堆实现的无界阻塞队列,元素按照优先级排序。

4. SynchronousQueue:一个不存储元素的阻塞队列,每个插入操作必须等待另一个线程的移除操作,反之亦然。

5. DelayQueue:基于PriorityQueue实现,用于存储实现了Delayed接口的元素,只有在延迟期满时才能取出元素。

这些实现类都提供了阻塞队列的常用方法,如put()、take()、offer()、poll()等,可以方便地实现生产者-消费者模式、任务调度等场景。

常用队列的使用

BlockingQueue是一个非常有用的数据结构,可以在多线程编程中实现线程间的协作和同步。下面是几个常用的BlockingQueue的使用方法:

  1. ArrayBlockingQueue:
BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
queue.put("Hello");
String s = queue.take();
System.out.println(s);           
  1. LinkedBlockingQueue:
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
queue.offer("Hello");
String s = queue.poll();
System.out.println(s);           
  1. PriorityBlockingQueue:
BlockingQueue<Integer> queue = new PriorityBlockingQueue<>();
queue.offer(2);
queue.offer(1);
queue.offer(3);
Integer n = queue.take();
System.out.println(n);           
  1. SynchronousQueue:
BlockingQueue<String> queue = new SynchronousQueue<>();
new Thread(() -> {
    try {
        queue.put("Hello");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}).start();
String s = queue.take();
System.out.println(s);           
  1. DelayQueue:
BlockingQueue<DelayedElement> queue = new DelayQueue<>();
queue.offer(new DelayedElement("Hello", 1000));
DelayedElement e = queue.take();
System.out.println(e.getData());           

PriorityBlockingQueue详解

PriorityBlockingQueue是Java集合框架中的一个阻塞队列实现类,它可以按照优先级对元素进行排序。在PriorityBlockingQueue中,元素必须实现Comparable接口或者在创建PriorityBlockingQueue时提供一个Comparator对象,用于比较元素的优先级。

PriorityBlockingQueue的特点:

  1. 内部使用堆来实现,保证元素的顺序性和高效性。
  2. 是一个无界队列,即队列大小可以动态增长,只受系统资源限制。
  3. 支持多线程环境下的并发访问,提供了阻塞和非阻塞两种操作方式。
  4. 不允许插入null元素。

PriorityBlockingQueue的常用方法:

  1. add(E e) / offer(E e):添加元素e到队列中。
  2. take():移除并返回队列头部的元素,如果队列为空,则阻塞等待。
  3. poll():移除并返回队列头部的元素,如果队列为空,则返回null。
  4. peek():返回队列头部的元素,但不移除。
  5. clear():清空队列中的元素。
  6. size():返回队列中的元素个数。

PriorityBlockingQueue的使用示例:

PriorityBlockingQueue<Integer> queue = new PriorityBlockingQueue<>();
queue.offer(3);
queue.offer(1);
queue.offer(2);
System.out.println(queue.poll()); // 1
System.out.println(queue.poll()); // 2
System.out.println(queue.poll()); // 3           

在上面的示例中,我们向PriorityBlockingQueue中添加了3个元素,然后依次取出元素,并按照优先级从小到大输出。优先级的比较是通过元素的自然顺序或Comparator对象来实现的。

Comparable接口

Comparable接口是Java中的一个接口,它定义了一个compareTo()方法,用于比较当前对象和另一个对象的大小关系。实现了Comparable接口的类可以进行自然排序,即按照对象的默认顺序进行排序,例如数字从小到大、字符串按照字典顺序等。

Comparable接口的定义如下:

public interface Comparable<T> {
    public int compareTo(T o);
}           

其中,compareTo方法返回一个整数值,表示当前对象和参数对象之间的大小关系。如果当前对象小于参数对象,则返回负数;如果当前对象等于参数对象,则返回0;如果当前对象大于参数对象,则返回正数。

实现了Comparable接口的类可以直接调用Collections.sort()方法或Arrays.sort()方法进行排序。例如,如果我们有一个Person类,其中有一个age属性,实现了Comparable接口如下:

public class Person implements Comparable<Person> {
    private int age;

    public Person(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    @Override
    public int compareTo(Person o) {
        return this.age - o.age;
    }
}           

在上面的代码中,我们实现了compareTo方法,按照age属性的大小进行比较。然后可以用以下代码进行排序:

List<Person> persons = new ArrayList<>();
persons.add(new Person(20));
persons.add(new Person(18));
persons.add(new Person(25));
Collections.sort(persons);           

在这个例子中,我们将三个Person对象添加到一个ArrayList中,然后调用Collections.sort()方法进行排序。由于Person类实现了Comparable接口,因此可以直接调用sort()方法进行自然排序。

总之,Comparable接口是Java集合框架中非常重要的一个接口,它可以帮助我们实现对象的自然排序。

Comparator接口的使用

Comparator是Java集合框架中的一个接口,用于定义对象之间的比较规则,可以通过实现Comparator接口来实现自定义的比较规则。与Comparable接口不同的是,Comparator接口可以用于对任意类型的对象进行比较,而不需要修改对象类的定义。

Comparator接口的定义如下:

public interface Comparator<T> {
    int compare(T o1, T o2);
    boolean equals(Object obj);
}           

其中,compare方法用于比较两个对象的大小关系,如果o1小于o2,则返回负数;如果o1等于o2,则返回0;如果o1大于o2,则返回正数。equals方法用于比较两个对象是否相等,通常不需要实现。

Comparator接口的实现类通常可以作为参数传递给Java集合框架中的排序方法,例如Collections.sort()方法或Arrays.sort()方法。下面是一个使用Comparator接口实现自定义比较规则的例子:

public class Person {
    private int age;
    private String name;

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public String getName() {
        return name;
    }
}

public class PersonComparator implements Comparator<Person> {
    @Override
    public int compare(Person o1, Person o2) {
        int result = o1.getAge() - o2.getAge();
        if (result == 0) {
            result = o1.getName().compareTo(o2.getName());
        }
        return result;
    }
}

// 使用PersonComparator对Person对象进行排序
List<Person> persons = new ArrayList<>();
persons.add(new Person(20, "Alice"));
persons.add(new Person(18, "Bob"));
persons.add(new Person(25, "Charlie"));
Collections.sort(persons, new PersonComparator());           

在这个例子中,我们实现了一个PersonComparator类,实现了Comparator接口中的compare方法。在compare方法中,我们首先按照age属性的大小进行比较,如果age相等,则按照name属性进行比较。然后可以用以下代码进行排序:

Collections.sort(persons, new PersonComparator());           

在这个例子中,我们将三个Person对象添加到一个ArrayList中,然后调用Collections.sort()方法进行排序。由于我们传入了一个PersonComparator实例,因此排序会按照我们自定义的规则进行。

总之,Comparator接口是Java集合框架中非常重要的一个接口,它可以帮助我们实现自定义的比较规则,适用于一些需要特定排序顺序的场景。

DelayQueue详解

DelayQueue是Java集合框架中的一个阻塞队列实现类,它可以按照延迟时间对元素进行排序。在DelayQueue中,元素必须实现Delayed接口,Delayed接口定义了getDelay()方法,用于返回元素的延迟时间。

DelayQueue的特点:

  1. 内部使用PriorityQueue来实现,保证元素的顺序性和高效性。
  2. 只有在延迟时间到达时才能从队列中取出元素。
  3. 是一个无界队列,即队列大小可以动态增长,只受系统资源限制。
  4. 支持多线程环境下的并发访问,提供了阻塞和非阻塞两种操作方式。
  5. 不允许插入null元素。

DelayQueue的常用方法:

  1. put(E e):添加元素e到队列中。
  2. take():移除并返回队列头部的元素,如果队列为空,则阻塞等待。
  3. poll():移除并返回队列头部的元素,如果队列为空,则返回null。
  4. peek():返回队列头部的元素,但是不会从队列中移除。
  5. size():返回队列中元素的数量。

下面是一个使用DelayQueue实现延迟任务的例子:

public class DelayedTask implements Delayed {
    private String name;
    private long endTime;

    public DelayedTask(String name, long delay) {
        this.name = name;
        this.endTime = System.currentTimeMillis() + delay;
    }

    @Override
    public long getDelay(TimeUnit unit) {
        long diff = endTime - System.currentTimeMillis();
        return unit.convert(diff, TimeUnit.MILLISECONDS);
    }

    @Override
    public int compareTo(Delayed o) {
        long diff = this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS);
        return (int) diff;
    }

    public String getName() {
        return name;
    }
}

public class DelayedTaskDemo {
    public static void main(String[] args) throws InterruptedException {
        DelayQueue<DelayedTask> queue = new DelayQueue<>();
        queue.put(new DelayedTask("task1", 5000));
        queue.put(new DelayedTask("task2", 3000));
        queue.put(new DelayedTask("task3", 8000));
        while (!queue.isEmpty()) {
            DelayedTask task = queue.take();
            System.out.println(task.getName() + " is executed at " + new Date());
        }
    }
}           

在这个例子中,我们定义了一个DelayedTask类,实现了Delayed接口。在DelayedTask类中,我们定义了一个endTime属性,表示任务的结束时间,然后实现了getDelay()方法和compareTo()方法。

在main方法中,我们创建了一个DelayQueue对象,并向其中添加了三个DelayedTask对象,分别表示三个延迟任务。然后我们使用while循环从队列中取出元素,并执行对应的任务。

在运行这个程序时,我们会发现任务按照延迟时间的顺序执行,即先执行task2,然后执行task1,最后执行task3。

总之,DelayQueue是一个非常有用的阻塞队列实现类,它可以帮助我们实现延迟任务的调度等场景。在实际应用中,我们可以根据实际需求来定义Delayed接口的实现类,并使用DelayQueue来管理这些延迟任务。

阻塞队里中获取元素与添加元素方法有哪些不同

BlockingQueue接口中定义了很多方法,下面是一些常用的方法以及它们的不同点:

  1. put(E e)和add(E e)

这两个方法都是用于向队列中添加元素的方法。不同之处在于,当队列已满时,put方法会一直阻塞直到队列有空闲位置,而add方法则会抛出IllegalStateException异常。

  1. take()和remove()

这两个方法都是用于从队列中取出元素的方法。不同之处在于,当队列为空时,take方法会一直阻塞直到队列中有元素可取,而remove方法则会抛出NoSuchElementException异常。

  1. offer(E e)和offer(E e, long timeout, TimeUnit unit)

这两个方法都是用于向队列中添加元素的方法。不同之处在于,当队列已满时,offer方法会立即返回false,而offer方法还可以设置超时时间,如果在指定时间内队列仍然没有空闲位置,则返回false。

  1. poll()和poll(long timeout, TimeUnit unit)

这两个方法都是用于从队列中取出元素的方法。不同之处在于,当队列为空时,poll方法会立即返回null,而poll方法还可以设置超时时间,如果在指定时间内队列仍然没有元素可取,则返回null。

  1. remainingCapacity()

这个方法用于返回队列中剩余的可用空间,不同的实现类可能会有不同的实现方式。

总之,BlockingQueue是一个非常有用的接口,它提供了一组阻塞队列的操作方法,可以帮助我们实现多线程并发场景下的数据交换和协调。在实际应用中,我们可以根据实际需求选择合适的实现类,并使用其中的方法来完成对队列的操作。

继续阅读