Java阻塞队列和非阻塞队列
什么是阻塞与非阻塞
阻塞和非阻塞指的是调用者在等待返回结果时的状态。阻塞时,在调用结果返回前,当前线程会被挂起,并在得到结果之后返回。非阻塞时,如果不能立刻得到结果,则该调用者不会阻塞当前线程。因此对应非阻塞的情况,调用者需要定时轮询查看处理状态。同步和异步指具体的通信机制。同步时调用者等待返回结果。异步时,被调用者通过回调等形式通知调用者。
Java阻塞和释放阻塞的几种实现方式
1、sleep() 方法
sleep(毫秒),指定以毫秒为单位的时间,使线程在该时间内进入线程阻塞状态,期间得不到cpu的时间片,等到时间过去了,线程重新进入可执行状态。(暂停线程,不会释放锁)
2、suspend() 和 resume() 方法
挂起和唤醒线程,suspend e()使线程进入阻塞状态,只有对应的resume e()被调用的时候,线程才会进入可执行状态。(不建议用,容易发生死锁)
3、yield() 方法
会使的线程放弃当前分得的cpu时间片,但此时线程任然处于可执行状态,随时可以再次分得cpu时间片。yield()方法只能使同优先级的线程有执行的机会。调用 yield()的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程。(暂停当前正在执行的线程,并执行其他线程,且让出的时间不可知)
4、join()方法
也叫线程加入。是当前线程A调用另一个线程B的join()方法,当前线程转A入阻塞状态,直到线程B运行结束,线程A才由阻塞状态转为可执行状态。
5、wait() 和 notify() 方法
两个方法搭配使用,wait()使线程进入阻塞状态,调用notify()时,线程进入可执行状态。wait()内可加或不加参数,加参数时是以毫秒为单位,当到了指定时间或调用notify()方法时,进入可执行状态。属于Object类,而不属于Thread类,wait()会先释放锁住的对象,然后再执行等待的动作。由于wait()所等待的对象必须先锁住,因此,它只能用在同步化程序段或者同步化方法内,否则,会抛出异常IllegalMonitorStateException。
Java阻塞和释放阻塞的例子
Java BlokingQueue 详解
抛出异常 | 特殊值 | 阻塞 | 超时 | |
---|---|---|---|---|
插入 | add(e) | offer(e) | put(e) | offer(e, time, unit) |
移除 | remove() | poll() | take() | poll(time, unit) |
检查 | element() | peek() | 不可用 | 不可用 |
这里使用重点使用了wait() 和 notify() 方法, BlockingQueue里的put(),take()方法。
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class BlockingQueueTest {
private static final int count = 10;
//生产者
public static class ProductThread implements Runnable {
private BlockingQueue<Integer> queue;
public ProductThread(BlockingQueue<Integer> queue) {
this.queue = queue;
}
public void run(){
while(true){
synchronized (queue) {
try {
while (queue.size() == 10) {
System.out.println("队列已满");
queue.notify();
queue.wait();
}
queue.offer(5);
System.out.println(Thread.currentThread()+"生产了一个产品---队列已有元素:"+queue.size()+"个,剩余:"+ (count - queue.size()));
Thread.sleep(1000);
}catch (InterruptedException e) {
queue.notify();
}
}
}
}
}
//消费者
public static class ConsumeThread implements Runnable {
private BlockingQueue<Integer> queue;
public ConsumeThread(BlockingQueue<Integer> queue) {
this.queue = queue;
}
public void run(){
while(true){
synchronized (queue) {
try {
while (queue.size() == 0) {
System.out.println("队列为空");
queue.notify();
queue.wait();
}
queue.take();
System.out.println(Thread.currentThread()+"消费了一个产品---队列已有元素:"+queue.size()+"个,剩余:"+ (count - queue.size()));
Thread.sleep(1000);
}catch (InterruptedException e) {
queue.notify();
}
}
}
}
}
public static void main(String[] args) {
//大小为10的循环数组阻塞队列
BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(count);
new Thread(new ProductThread(queue)).start();
new Thread(new ConsumeThread(queue)).start();
}
}
它会依次建创建好的队列中加入元素,元素已满时,生产者ProductThread阻塞,释放消费者ConsumeThread释放,依次交替阻塞释放。如果想更好的理解阻塞还是释放,可以注释掉其中一个queue.notify();,或者注释掉queue.wait();。
元素已满时,生产者ProductThread阻塞,释放消费者ConsumeThread释放,依次交替阻塞释放。如果想更好的理解阻塞还是释放,可以注释掉其中一个queue.notify();,或者注释掉queue.wait();。