阻塞与非阻塞:
阻塞:
阻塞调用是没有获得资源则挂起进程,被挂起的进程进入休眠状态,调用的函数只有在得到结果之后才返回,进程继续。
对象是否处于阻塞模式和函数是不是阻塞调用有很强的相关性,但并不是一一对应的;阻塞对象上可以有非阻塞的调用方式。
我们可以通过一定的API去轮询状态,在适当的时候调用阻塞函数,就可以避免阻塞。
非阻塞:
非阻塞是不能进行设备操作时不挂起,或返回,或反复查询,直到可以进行操作为止,被调用的函数不会阻塞当前进程,而会立刻返回。
对于非阻塞对象,调用的函数也可以锁机制进入阻塞调用
注意:
阻塞不是低效率,如果设备驱动不阻塞,用户想获取资源只能不断查询,小号CPU阻塞访问时,不能获取资源的进程将进入休眠,将CPU资源让给其他资源。
阻塞的进程会进入休眠状态,因此,必须确保有一个地方能唤醒休眠的进程。唤醒进程的地方最大可能发生在终端里面,因为硬件资源的获得往往伴随着一个终端。
案例代码:主线程生产日志数据,由多线程去消费
public class ArrayBlockingQueueTest { public static void main(String[] args) throws Exception { //创建一个固定大小的队列 final BlockingQueue<String> queue = new ArrayBlockingQueue<String>(1); //生产数据 for(int i=0;i<100000;i++){ queue.put(i+1+""); } //创建10个消费者 for(int i=0;i<10;i++){ new Thread(new Runnable(){ @Override public void run() { while(true){ try { String log = queue.take(); System.out.println(Thread.currentThread().getName()+"=>"+log); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } } }
结果输出:
Thread-0=>1
Thread-3=>3
Thread-2=>4
Thread-1=>2
Thread-3=>6
Thread-1=>7
Thread-0=>5
Thread-1=>8
Thread-2=>9
Thread-2=>10
Thread-3=>11
Thread-3=>12
Thread-1=>13
Thread-2=>14
put原理:
/** * Inserts the specified element at the tail of this queue, waiting * for space to become available if the queue is full. * * @throws InterruptedException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public void put(E e) throws InterruptedException { checkNotNull(e); final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { while (count == items.length) notFull.await(); enqueue(e); } finally { lock.unlock(); } }
take原理:
public E take() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { while (count == 0) notEmpty.await(); return dequeue(); } finally { lock.unlock(); } }