BlockingQueue常用实现类
Java中的BlockingQueue是一个接口,它定义了一组阻塞队列的操作方法。它的实现类包括:
1. ArrayBlockingQueue:基于数组实现的有界阻塞队列,必须指定队列大小。
2. LinkedBlockingQueue:基于链表实现的可选有界阻塞队列,如果不指定队列大小,则默认大小为Integer.MAX_VALUE。
3. PriorityBlockingQueue:基于堆实现的无界阻塞队列,元素按照优先级排序。
4. SynchronousQueue:一个不存储元素的阻塞队列,每个插入操作必须等待另一个线程的移除操作,反之亦然。
5. DelayQueue:基于PriorityQueue实现,用于存储实现了Delayed接口的元素,只有在延迟期满时才能取出元素。
这些实现类都提供了阻塞队列的常用方法,如put()、take()、offer()、poll()等,可以方便地实现生产者-消费者模式、任务调度等场景。
常用队列的使用
BlockingQueue是一个非常有用的数据结构,可以在多线程编程中实现线程间的协作和同步。下面是几个常用的BlockingQueue的使用方法:
- ArrayBlockingQueue:
BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
queue.put("Hello");
String s = queue.take();
System.out.println(s);
- LinkedBlockingQueue:
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
queue.offer("Hello");
String s = queue.poll();
System.out.println(s);
- PriorityBlockingQueue:
BlockingQueue<Integer> queue = new PriorityBlockingQueue<>();
queue.offer(2);
queue.offer(1);
queue.offer(3);
Integer n = queue.take();
System.out.println(n);
- 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);
- 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的特点:
- 内部使用堆来实现,保证元素的顺序性和高效性。
- 是一个无界队列,即队列大小可以动态增长,只受系统资源限制。
- 支持多线程环境下的并发访问,提供了阻塞和非阻塞两种操作方式。
- 不允许插入null元素。
PriorityBlockingQueue的常用方法:
- add(E e) / offer(E e):添加元素e到队列中。
- take():移除并返回队列头部的元素,如果队列为空,则阻塞等待。
- poll():移除并返回队列头部的元素,如果队列为空,则返回null。
- peek():返回队列头部的元素,但不移除。
- clear():清空队列中的元素。
- 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的特点:
- 内部使用PriorityQueue来实现,保证元素的顺序性和高效性。
- 只有在延迟时间到达时才能从队列中取出元素。
- 是一个无界队列,即队列大小可以动态增长,只受系统资源限制。
- 支持多线程环境下的并发访问,提供了阻塞和非阻塞两种操作方式。
- 不允许插入null元素。
DelayQueue的常用方法:
- put(E e):添加元素e到队列中。
- take():移除并返回队列头部的元素,如果队列为空,则阻塞等待。
- poll():移除并返回队列头部的元素,如果队列为空,则返回null。
- peek():返回队列头部的元素,但是不会从队列中移除。
- 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接口中定义了很多方法,下面是一些常用的方法以及它们的不同点:
- put(E e)和add(E e)
这两个方法都是用于向队列中添加元素的方法。不同之处在于,当队列已满时,put方法会一直阻塞直到队列有空闲位置,而add方法则会抛出IllegalStateException异常。
- take()和remove()
这两个方法都是用于从队列中取出元素的方法。不同之处在于,当队列为空时,take方法会一直阻塞直到队列中有元素可取,而remove方法则会抛出NoSuchElementException异常。
- offer(E e)和offer(E e, long timeout, TimeUnit unit)
这两个方法都是用于向队列中添加元素的方法。不同之处在于,当队列已满时,offer方法会立即返回false,而offer方法还可以设置超时时间,如果在指定时间内队列仍然没有空闲位置,则返回false。
- poll()和poll(long timeout, TimeUnit unit)
这两个方法都是用于从队列中取出元素的方法。不同之处在于,当队列为空时,poll方法会立即返回null,而poll方法还可以设置超时时间,如果在指定时间内队列仍然没有元素可取,则返回null。
- remainingCapacity()
这个方法用于返回队列中剩余的可用空间,不同的实现类可能会有不同的实现方式。
总之,BlockingQueue是一个非常有用的接口,它提供了一组阻塞队列的操作方法,可以帮助我们实现多线程并发场景下的数据交换和协调。在实际应用中,我们可以根据实际需求选择合适的实现类,并使用其中的方法来完成对队列的操作。