1.什么是阻塞队列?
2.为什么用,有什么好处?
3.BlockingQueue的核心方法
3.1抛出异常组
package com.queue;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
*
*
*
* 1.队列
*
*
* 2.阻塞队列
* 2.1阻塞队列有没有好的一面
* 2.2不得不足阻塞你会如何管理
*/
public class BlockingQueueDemo {
public static void main(String[] args) {
// List list= new ArrayList<>();
BlockingQueue<String> blockingQueue =new ArrayBlockingQueue<String>(3);
System.out.println(blockingQueue.add("a"));
System.out.println(blockingQueue.add("b"));
System.out.println(blockingQueue.add("c"));
/**
* 异常输出
* true
* true
* true
*
* Exception in thread "main" java.lang.IllegalStateException: Queue full
* at java.util.AbstractQueue.add(AbstractQueue.java:98)
* at java.util.concurrent.ArrayBlockingQueue.add(ArrayBlockingQueue.java:312)
* at com.queue.BlockingQueueDemo.main(BlockingQueueDemo.java:28)
*/
System.out.println(blockingQueue.add("d"));
/**
* 检查头元素,先到先得 输出 a
*/
System.out.println(blockingQueue.element());
/**
* Exception in thread "main" java.util.NoSuchElementException
* at java.util.AbstractQueue.remove(AbstractQueue.java:117)
* at com.queue.BlockingQueueDemo.main(BlockingQueueDemo.java:45)
*/
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
}
}
3.2 特殊值
package com.queue;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
*
*
*
* 1.队列
*
*
* 2.阻塞队列
* 2.1阻塞队列有没有好的一面
* 2.2不得不足阻塞你会如何管理
*/
public class BlockingQueueDemo {
public static void main(String[] args) {
// List list= new ArrayList<>();
BlockingQueue<String> blockingQueue =new ArrayBlockingQueue<String>(3);
System.out.println(blockingQueue.offer("a"));
System.out.println(blockingQueue.offer("b"));
System.out.println(blockingQueue.offer("c"));
/**
* 输出
* true
* true
* true
* false
*/
System.out.println(blockingQueue.offer("z"));
/**
* 输出 a
*/
System.out.println(blockingQueue.peek());
/**
* 输出
* a
* b
* c
* null
*
* 该对列就3个位置 取第四个位置的时候取不到,不会报异常比第一组温和 输出 null
*/
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
}
}
3.3 阻塞
package com.queue;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
*
*
*
* 1.队列
*
*
* 2.阻塞队列
* 2.1阻塞队列有没有好的一面
* 2.2不得不足阻塞你会如何管理
*/
public class BlockingQueueDemo {
public static void main(String[] args) throws Exception{
// List list= new ArrayList<>();
BlockingQueue<String> blockingQueue =new ArrayBlockingQueue<String>(3);
blockingQueue.put("a");
blockingQueue.put("b");
blockingQueue.put("c");
System.out.println("======================================");
/**
* 当阻塞对列满时候往元素里面
* put元素,队列转会一直阻塞生产线程线程
*/
blockingQueue.put("d");
blockingQueue.take();
blockingQueue.take();
blockingQueue.take();
/**
* 当对列的元素为空的时候,消费线程会从对列里面取元素,此时对列会阻塞消费线程
*/
blockingQueue.take();
}
}
3.4 超时
package com.queue;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
/**
*
*
*
* 1.队列
*
*
* 2.阻塞队列
* 2.1阻塞队列有没有好的一面
* 2.2不得不足阻塞你会如何管理
*/
public class BlockingQueueDemo {
public static void main(String[] args) throws Exception{
// List list= new ArrayList<>();
BlockingQueue<String> blockingQueue =new ArrayBlockingQueue<String>(3);
System.out.println(blockingQueue.offer("a", 2L, TimeUnit.SECONDS));
System.out.println(blockingQueue.offer("b", 2L, TimeUnit.SECONDS));
System.out.println(blockingQueue.offer("c", 2L, TimeUnit.SECONDS));
/**
* 等两秒钟后才可以插入,过时不候
*/
System.out.println(blockingQueue.offer("d", 2L, TimeUnit.SECONDS));
}
}
4. SynchronousQueue
不存储元素的阻塞队列,也即单个元素的对列
package com.queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
/**
* SynchronousQueueDemo 演示
*/
public class SynchronousQueueDemo {
public static void main(String[] args) {
BlockingQueue<String> blockingQueue = new SynchronousQueue<>();
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + "\t put 1");
blockingQueue.put("1");
System.out.println(Thread.currentThread().getName() + "\t put 2");
blockingQueue.put("2");
System.out.println(Thread.currentThread().getName() + "\t put 3");
blockingQueue.put("3");
} catch (Exception e) {
e.printStackTrace();
}
}, "AAA").start();
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(5);
System.out.println(Thread.currentThread().getName()+"\t "+ blockingQueue.take());
TimeUnit.SECONDS.sleep(5);
System.out.println(Thread.currentThread().getName()+"\t "+ blockingQueue.take());
TimeUnit.SECONDS.sleep(5);
System.out.println(Thread.currentThread().getName()+"\t "+ blockingQueue.take());
} catch (Exception e) {
e.printStackTrace();
}
}, "BBB").start();
}
}
结果输出:
AAA put 1
BBB 1
AAA put 2
BBB 2
AAA put 3
BBB 3
5.用途,应在在哪里?
5.1生产者消费者模式
package com.thread;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class ShareData {
private int number = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void increment() throws Exception {
lock.lock();
try {
//判断 一定要用while 防止虚假唤醒
while (number != 0) {
//等待不能生产
condition.await();
}
number++;
System.out.println(Thread.currentThread().getName() + "\t" + number);
//通知唤醒
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void decrement() throws Exception {
lock.lock();
try {
//判断
while (number == 0) {
//等待不能生产
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName() + "\t" + number);
//通知唤醒
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
/**
* 一个初始值的变量,两个线程对它进行操作,一个加 1 一个减 1
* 生产者,消费者模式
* <p>
* 多线程开发口诀
* 1. 高并发前提一定是高内聚,低耦合
* 2.线程操纵资源类
* <p>
* 3.判断,干活,唤醒通知
* <p>
* 4.严防多线程下的虚假唤醒
*/
public class ProdConstumerDemo {
public static void main(String[] args) {
ShareData shareData = new ShareData();
new Thread(() -> {
for (int i = 1; i <= 5; i++) {
try {
shareData.increment();
} catch (Exception e) {
e.printStackTrace();
}
}
}, "AA").start();
new Thread(() -> {
for (int i = 1; i <= 5; i++) {
try {
shareData.decrement();
} catch (Exception e) {
e.printStackTrace();
}
}
}, "BB").start();
//=======================================
// new Thread(() -> {
// for (int i = 1; i <= 5; i++) {
// try {
// shareData.increment();
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// }, "CC").start();
//
// new Thread(() -> {
// for (int i = 1; i <= 5; i++) {
// try {
// shareData.decrement();
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// }, "DD").start();
}
}
输出:
AA 1
BB 0
AA 1
BB 0
AA 1
BB 0
AA 1
BB 0
AA 1
BB 0