zoukankan      html  css  js  c++  java
  • Java多线程学习(一)

    在Java多线程应用中,队列的使用率很高,多数生产消费模型的首选数据结构就是队列。Java提供的线程安全的Queue可以分为阻塞队列和非阻塞队列,其中阻塞队列的典型例子是BlockingQueue,非阻塞队列的典型例子是ConcurrentLinkedQueue,在实际应用中要根据实际需要选用阻塞队列或者非阻塞队列。

      线程安全的类 ,指的是类内共享的全局变量的访问必须保证是不受多线程形式影响的。如果由于多线程的访问(比如修改、遍历、查看)而使这些变量结构被破坏或者针对这些变量操作的原子性被破坏,则这个类就不是线程安全的。

      我这里主要学习分析下BlockingQueue和ConcurrentLinkedQueue。

    一、BlockingQueue

    BlockingQueue提供的常用方法:

    可能报异常	返回布尔值	可能阻塞	设定等待时间
    

    入队 add(e) offer(e) put(e) offer(e, timeout, unit)
    出队 remove() poll() take() poll(timeout, unit)
    查看 element() peek() 无 无
    add(e) remove() element() 方法不会阻塞线程。当不满足约束条件时,会抛出IllegalStateException 异常。例如:当队列被元素填满后,再调用add(e),则会抛出异常。
    offer(e) poll() peek() 方法即不会阻塞线程,也不会抛出异常。例如:当队列被元素填满后,再调用offer(e),则不会插入元素,函数返回false。
    要想要实现阻塞功能,需要调用put(e) take() 方法。当不满足约束条件时,会阻塞线程
    这里就ArrayBlockingQueue的源码学习一下:

    第一类方法,其实是调用第二类方法,只是不成功就抛异常而已。
    public boolean add(E e) {
    if (offer(e))
    return true;
    else
    throw new IllegalStateException("Queue full");//队列已满,抛异常
    }

    public E remove() {
    E x = poll();
    if (x != null)
    return x;
    else
    throw new NoSuchElementException();//队列为空,抛异常
    }

    第二类方法,很标准的ReentrantLock使用方式(不熟悉的朋友看一下这个帖子http://hellosure.iteye.com/blog/1121157)。
    注:先不看阻塞与否,这ReentrantLock的使用方式就能说明这个类是线程安全类。

    public boolean offer(E e) {
    if (e == null)throw new NullPointerException();
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
    if (count == items.length)//队列已满,返回false
    return false;
    else {
    insert(e);//insert方法中发出了notEmpty.signal();
    return true;
    }
    } finally {
    lock.unlock();
    }
    }
    
    public E poll() {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
    if (count == 0)//队列为空,返回false
    return null;
    E x = extract();//extract方法中发出了notFull.signal();
    return x;
    } finally {
    lock.unlock();
    }
    }

    第三类方法,这里面涉及到Condition类,简要提一下,
    await方法指:造成当前线程在接到信号或被中断之前一直处于等待状态。
    signal方法指:唤醒一个等待线程。

    public void put(E e)throws InterruptedException {
    if (e == null)throw new NullPointerException();
    final E[] items = this.items;
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
    try {
    while (count == items.length)//如果队列已满,等待notFull这个条件,这时当前线程被阻塞
    notFull.await();
    } catch (InterruptedException ie) {
    notFull.signal(); //唤醒受notFull阻塞的当前线程
    throw ie;
    }
    insert(e);
    } finally {
    lock.unlock();
    }
    }
    
    public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
    try {
    while (count == 0)//如果队列为空,等待notEmpty这个条件,这时当前线程被阻塞
    notEmpty.await();
    } catch (InterruptedException ie) {
    notEmpty.signal();//唤醒受notEmpty阻塞的当前线程
    throw ie;
    }
    E x = extract();
    return x;
    } finally {
    lock.unlock();
    }
    }
  • 相关阅读:
    太鼓达人
    DB2中循环日期跑数据
    DB2分区表删除和添加分区
    DB2日常运维之总结(转)
    oracle SQL not in null,单列,复合列
    利用rlwrap配置linux下oracle sqlplus 历史记录回调
    Oracle非默认监听的处理会遇到的问题以及处理方法
    Sqlserver循环嵌套
    rman全备份异机恢复
    Windows系统下Oracle数据库冷备
  • 原文地址:https://www.cnblogs.com/andyfengzp/p/6016072.html
Copyright © 2011-2022 走看看