java 多线程协作肯定因为共享对象,实现原理是基于线程挂起和线程恢复。

wait notify condition 都是 基于锁对象产生的衍生方法,多线程之间可以依靠这些方法实现线程协作。

synchronized 的锁原理是在共享对象头里添加标记和对象监控器,这些都是jvm 内部实现的。

而 lock 的锁原理是 独立于共享对象之外 新建一个锁监控对象(锁对象就类似于synchronized 的monitor),需要用户自定义。

synchronized 底层通过monitor 来存储共享对象的并发使用情况,多个线程之间可以通过使用 共享对象.wait 和 共享对象.notify 来实现 多线程 切换。

Lock 也可以实现Object中的notify与wait功能,那就是:Condition

   private Lock lock = new ReentrantLock();
   private Condition condition = lock.newCondition();//多线程操作共享对象使用的锁。


当使用如下的方法就相当于使用Object类的 wait

condition.await();
使用如下方法相当于使用Object类的 notify

condition.signal();    
 

synchronized 和wait notify 的使用:

List list=new Arraylist();//共享对象。

synchronized String  get(){

     if(CollectionUtils.isnotempty(list)){

        list.notify();

       return list.get(0);

     }else{

         list.wait();

    }

}

synchronized String  set(){

     if(CollectionUtils.isnotfull(list)){

        list.add("asdasd);

     list.notify();

     }      else{

list.wait();  

}

}

 

Lock 和 Condition 的使用

List list=new Arraylist(); //共享对象。

private Lock lock = new ReentrantLock();

private Condition condition = lock.newCondition();/

String  get(){

    lock.lock();
        try{
            if(CollectionUtils.isnotempty(list)){

                condition.signal(); return list.get(0);

            }else{condition.await() }
        }catch(Exception e){
            catch exception...
        }finally{
            lock.unlock();
        }

}

String  set(){

   lock.lock();
        try{
            if(CollectionUtils.isnotfull(list)){

                condition.signal(); list.add("ssda);

            }else{condition.await() }
        }catch(Exception e){
            catch exception...
        }finally{
            lock.unlock();
        }

}

以上是如果只有一个读线程和一个写线程的情况下,我们可以这样处理,但是如果有 多个读线程,多个写线程,

如果写的时候发现满了,想要唤醒读线程,但是 notify根本不知道自己唤醒的是读线程,还是写线程。这时候我们就可以用condition 实现了,同一个lock 上可以建立 多个condition ,代码优化如下:

List list=new Arraylist(); //共享对象。

private Lock lock = new ReentrantLock();

private Condition read = lock.newCondition();/

private Condition write = lock.newCondition();/

String  get(){

    lock.lock();
        try{
            if(CollectionUtils.isnotempty(list)){

                 if(list.size==1){ write.signal()}

                 return list.get(0);

            }else{read.await()}
        }catch(Exception e){
            catch exception...
        }finally{
            lock.unlock();
        }

}

String  set(){

   lock.lock();
        try{
            if(CollectionUtils.isnotfull(list)){

              if(list.size==maxsize){ read.signal()}

               list.add("ssda);

            }else{write.await()}
        }catch(Exception e){
            catch exception...
        }finally{
            lock.unlock();
        }

}

对象监视器里的队列分为 等待队列 和正在处理的 队列,正在处理的队列处理完之后发送一个信号通知到等待队列,等待队列的线程收到消息开始处理。

之前使用wait 和notify 实现,但是以上说明了 缺点,当多个读和写线程都在等待的时候,并不能确定唤醒的是哪种线程。

现在用condition 可以把 读队列和写队列 分开,分成了2个队列。通知的时候也只要通知特定队列的线程就可以了。

condition 就是 阻塞线程分组的依据。一部分线程在等待读操作,一部分线程在等待写操作。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐