zoukankan      html  css  js  c++  java
  • 并发编程(三):从AQS到CountDownLatch与ReentrantLock

    一、目录

         1、AQS简要分析
         2、谈CountDownLatch
         3、谈ReentrantLock
         4、谈消费者与生产者模式(notfiyAll/wait、signAll/await、condition)

    二、AQS简要分析

    问题:AQS是什么?有什么用?
     
    AQS是什么?
         字面上看,它被称为抽象队列式的同步器(AbstractQueuedSynchronizer)。简单说,它就是一个同步队列容器。
     
    AQS有什么用?
    1. 为什么会产生ArrayList、LinkedList、HashMap这些容器?它们底层实现无非都是对数组、链表、树的操作,至于它们的产生,就是因为对编程人员对于数组、链表、树的增删改查操作非常繁琐而提出的解决方案。
    2. 那为什么会产生AQS呢?谈到同步,大家最容易想到的就是在多线程中如何确保安全的资源共享。那同步队列就是为了解决资源共享的同步容器。像上述容器一样,在顶层就设计好,编程人员只需要调用接口就能轻易实现复杂的资源共享问题。
     
    既然谈到资源共享,那同步容器怎么实现资源共享呢?
         AQS定义两种资源共享方式:Exclusive(独占、只有一个线程执行,如ReentrantLock)和Share(共享,多个线程可同时执行,如Semaphore/CountDownLatch)。
     
    那什么是独占式?
         在谈synchronized的资源共享实现方式的时候,当线程A访问共享资源的时候,其它的线程全部被堵塞,直到线程A读写完毕,其它线程才能申请同步互斥锁从而访问共享资源。如果之前看过我关于synchronized的讨论,这里应该不难理解,为了照顾未了解过的读者,再重新回顾一下。
         以RenentrantLock为例,如何知道共享资源是否有线程正在被访问呢?其实,它有一个state变量初始值为0,表示未锁定状态。当线程A访问的时候,state+1,就代表该线程锁定了共享资源,其他线程将无法访问,而当线程A访问完共享资源以后,state-1,直到state等于0,就将释放对共享变量的锁定,其他线程将可以抢占式或者公平式争夺。当然,它支持可重入,那什么是可重入呢?同一线程可以重复锁定共享资源,每锁定一次state+1,也就是锁定多次。说明:锁定多少次就要释放多少次。
     
    什么是共享式呢?
         以CountDownLatch为例,共享资源可以被N个线程访问,也就是初始化的时候,state就被指定为N(N与线程个数相等),线程countDown()一次,state会CAS减1,直到所有线程执行完(state=0),那些await()的线程将被唤醒去执行执行剩余动作。
         什么是CAS?CAS的定义为Compare-And-Swap,语义为比较并且交换。在深入理解JVM书中,谈到自旋锁,因为锁的堵塞释放对于cpu资源的损害很高,那么自旋锁就是当线程A访问共享资源的时候,其他线程并不放弃对锁的持有,它们在不停循环,不断尝试的获取锁,直到获得锁就停止循环,自旋锁是对于资源共享的一种优化手段,但是它适用于对锁持有时间比较短的情况。
     
    独占式lock流程(unlock同理):
    1. 调用自定义同步器的tryAcquire()尝试直接去获取资源,如果成功就返回。
    2. 没成功,则addWaiter()将线程加入等待队列的尾部,并标记为独享模式。
    3. acquireQueued()使线程在等待队列中休息,有机会时会去尝试获得资源。获得资源后返回。如果整个过程有中断过返回true,否则返回false。
    4. 如果线程在等待过程中中断过,它是不响应的。只是获得资源后才再进行自我中断selfInterrupt(),将中断补上。
     
    共享式流程(类似于独占式 ):
    1. tryAcquireShared()尝试获取资源,成功则直接返回。
    2. 失败则通过 doAcquireShared()进入等待队列,直到被唤醒或者中断并且成功获取资源才返回。
    3. 不同:独占式是只唤醒后继节点。共享式是唤醒后继,后继还会去唤醒它的后继,从而实现共享。

    以上是核心的关于CountDownLatch、ReentrantLock的分析。由于博主研究程度有限,想更深层次研究,请参考:Java并发AQS详解

     三、浅谈CountDownLatch

    CountDownLatch是什么? 有什么用?
         CountDownLatch是一个同步容器,但是有人叫它发令枪,也有人叫它门闩。初始化设定线程的个数,调用countDownLatch.await()阻塞所有线程,直到countDownLatch.countDown()为0,那么将继续执行剩余的操作。例如,跑步比赛,所有线程都await()在起跑线,当所有人告诉裁判准备好了,裁判发令枪一响,运动员开炮。门闩道理一样,门不开全给我等着!
     
         作用:为了实现同步共享数据的一种更加高效的解决办法。
    /**
     * CountDownLatch相当于指令枪或者门闩,所有线程都awit()阻塞在起跑线,只有countDown到state为0,其他线程才能往下运行。
     * @author qiuyongAaron
     */
    public class CountDownLatchDemo {
         private static final int PLAYER_NUM=5;
    
     </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) {
    
           CountDownLatch start</span>=<span style="color: #0000ff;">new</span> CountDownLatch(1<span style="color: #000000;">);
           CountDownLatch end </span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> CountDownLatch(PLAYER_NUM);
           Player [] players</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> Player[PLAYER_NUM];
    
           </span><span style="color: #0000ff;">for</span>(<span style="color: #0000ff;">int</span> i=0;i&lt;PLAYER_NUM;i++<span style="color: #000000;">)
                players[i]</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> Player(start, end, i);
           </span><span style="color: #008000;">//</span><span style="color: #008000;">指定线程个数的线程池!</span>
           ExecutorService exe=<span style="color: #000000;">Executors.newFixedThreadPool(PLAYER_NUM);
           </span><span style="color: #0000ff;">for</span><span style="color: #000000;">(Player player:players)
                exe.execute(player);
    
           System.out.println(</span>"比赛开始!"<span style="color: #000000;">);
           </span><span style="color: #008000;">//</span><span style="color: #008000;">比赛开始!</span>
    

    start.countDown();

           </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
                end.await();
           } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) {
                e.printStackTrace();
           }</span><span style="color: #0000ff;">finally</span><span style="color: #000000;">{
                System.out.println(</span>"比赛结束!"<span style="color: #000000;">);
                exe.shutdown();
           }
     }
    

    }

    class Player implements Runnable{
    private CountDownLatch start;
    private CountDownLatch end;
    private int id;

     Random random</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> Random();
     </span><span style="color: #0000ff;">public</span> Player(CountDownLatch start,CountDownLatch end,<span style="color: #0000ff;">int</span><span style="color: #000000;"> id) {
           </span><span style="color: #0000ff;">this</span>.start=<span style="color: #000000;">start;
           </span><span style="color: #0000ff;">this</span>.end=<span style="color: #000000;">end;
           </span><span style="color: #0000ff;">this</span>.id=<span style="color: #000000;">id;
     }
    
     @Override
     </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> run() {
           </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
                </span><span style="color: #008000;">//</span><span style="color: #008000;">等待比赛开始。</span>
    

    start.await();
    TimeUnit.SECONDS.sleep(random.nextInt(
    10));
    System.out.println(
    "Player-"+id+":arrived");
    }
    catch (InterruptedException e) {
    e.printStackTrace();
    }
    finally{
    //选手-id到达终点,end计数为0结束比赛!
    end.countDown();
    }
    }
    }

    //运行结果:
    比赛开始!
    Player
    -3:arrived
    Player
    -4:arrived
    Player
    -0:arrived
    Player
    -1:arrived
    Player
    -2:arrived
    比赛结束!

    三、谈ReentrantLock

    1、ReentrantLock是什么?有什么用?
    ReentrantLock跟synchronized作用差不多,是在于synchronized基础上的一种简易同步容器,并没有深层次的原理剖析。
     
    2、ReentrantLock的基础用法
    2.1 回顾synchronized如何实现线程同步。
    /**
     * 示例一:同步锁的使用
     * reentrantlock用于替代synchronized
     * 本例中由于m1锁定this,只有m1执行完毕的时候,m2才能执行
     * @author qiuyongAaron
     */
    public class ReentrantLockOne {
         public synchronized void m1(){
               for(int i=0;i<10;i++){
                    try {
                         TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                         e.printStackTrace();
                    }
                    System.out.println(i);
               }
         }
    
     </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">synchronized</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> m2(){
           System.out.println(</span>"hello m2!"<span style="color: #000000;">);
     }
    
     </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) {
           ReentrantLockOne lock</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> ReentrantLockOne();
    
           </span><span style="color: #0000ff;">new</span> Thread(()-&gt;lock.m1(),"t1"<span style="color: #000000;">).start();
    
           </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
                TimeUnit.SECONDS.sleep(</span>2<span style="color: #000000;">);
           } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) {
                e.printStackTrace();
           }
    
           </span><span style="color: #0000ff;">new</span> Thread(()-&gt;lock.m2(),"t2"<span style="color: #000000;">).start();
     }
    

    }

    Synchronized实现线程同步

     2.2 ReentrantLock实现线程同步-与synchronized作用一致!

    /**
     * 示例二:等价于同步锁
     * 使用reentrantlock可以完成同样的功能
     * 需要注意的是,必须要必须要必须要手动释放锁(重要的事情说三遍)
     * 使用syn锁定的话如果遇到异常,jvm会自动释放锁,但是lock必须手动释放锁,因此经常在finally中进行锁的释放
     * @author qiuyongAaron
     */
    public class ReentrantLockTwo {
         ReentrantLock lock =new ReentrantLock();
         public  void m1(){
               try {
                    lock.lock();
                    for(int i=0;i<10;i++){
                         TimeUnit.SECONDS.sleep(1);
                         System.out.println(i);
                    }
               } catch (InterruptedException e) {
                    e.printStackTrace();
               }finally{
                    lock.unlock();
               }
         }
    
     </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">synchronized</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> m2(){
           lock.lock();
           System.out.println(</span>"hello m2!"<span style="color: #000000;">);
           lock.unlock();
     }
    
     </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) {
           ReentrantLockTwo lock</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> ReentrantLockTwo();
    
           </span><span style="color: #0000ff;">new</span> Thread(()-&gt;lock.m1(),"t1"<span style="color: #000000;">).start();
    
           </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
                TimeUnit.SECONDS.sleep(</span>2<span style="color: #000000;">);
           } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) {
                e.printStackTrace();
           }
    
           </span><span style="color: #0000ff;">new</span> Thread(()-&gt;lock.m2(),"t2"<span style="color: #000000;">).start();
     }
    

    }

    ReentrantLock同步互斥
     2.3 ReentrantLock尝试获取锁,若指定时间无法获取锁放弃等待!
    /**
     * 示例三:tryLock
     * 使用reentrantlock可以进行“尝试锁定”tryLock,这样无法锁定,或者在指定时间内无法锁定,线程可以决定是否继续等待
     * @author qiuyongAaron
     */
    public class ReentrantLockThree {
         ReentrantLock lock=new ReentrantLock();
    
     </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> m1(){
           </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
                lock.lock();
                </span><span style="color: #0000ff;">for</span>(<span style="color: #0000ff;">int</span> i=0;i&lt;10;i++<span style="color: #000000;">){
                     TimeUnit.SECONDS.sleep(</span>1<span style="color: #000000;">);
                     System.out.println(i);
                }
           } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception e) {
                e.printStackTrace();
           }</span><span style="color: #0000ff;">finally</span><span style="color: #000000;">{
                lock.unlock();
           }
     }
    
     </span><span style="color: #0000ff;">boolean</span> locked=<span style="color: #0000ff;">false</span><span style="color: #000000;">;
     </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> m2(){
           </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
                lock.tryLock(</span>5<span style="color: #000000;">,TimeUnit.SECONDS);
                System.out.println(</span>"m2:"+<span style="color: #000000;">locked);
           } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception e) {
                e.printStackTrace();
           }</span><span style="color: #0000ff;">finally</span><span style="color: #000000;">{
                </span><span style="color: #0000ff;">if</span><span style="color: #000000;">(locked) lock.unlock();
           }
     }
    
     </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) {
           ReentrantLockThree lock</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> ReentrantLockThree();
    
           </span><span style="color: #0000ff;">new</span> Thread(()-&gt;lock.m1(),"t1"<span style="color: #000000;">).start();
    
           </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
                TimeUnit.SECONDS.sleep(</span>1<span style="color: #000000;">);
           } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) {
                e.printStackTrace();
           }
    
           </span><span style="color: #0000ff;">new</span> Thread(()-&gt;lock.m2(),"t2"<span style="color: #000000;">).start();
     }
    

    }

    ReentrantLock尝试获取锁

     2.4 指定公平锁或者抢占式锁

    /**
     * ReentrantLock还可以指定为公平锁
     * @author qiuyongAaron
     */
    public class ReentrantLockFive extends Thread{
    
     </span><span style="color: #008000;">//</span><span style="color: #008000;">默认false:为非公平锁  true:公平锁</span>
     ReentrantLock lock=<span style="color: #0000ff;">new</span><span style="color: #000000;"> ReentrantLock();
    
     @Override
     </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> run() {
           </span><span style="color: #0000ff;">for</span>(<span style="color: #0000ff;">int</span> i=0;i&lt;100;i++<span style="color: #000000;">){
                lock.lock();
                </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
                     TimeUnit.SECONDS.sleep(</span>1<span style="color: #000000;">);
                     System.out.println(Thread.currentThread().getName()</span>+"获得锁"+"-"+<span style="color: #000000;">i);
                } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) {
                     e.printStackTrace();
                }</span><span style="color: #0000ff;">finally</span><span style="color: #000000;">{
                     lock.unlock();
                }
           }
    
     }
    
     </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) {
           ReentrantLockFive lock</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> ReentrantLockFive();
           </span><span style="color: #0000ff;">new</span> Thread(lock,"t1"<span style="color: #000000;">).start();
           </span><span style="color: #0000ff;">new</span> Thread(lock,"t2"<span style="color: #000000;">).start();
     }
    

    }

    运行结果:
    //非公平锁
    t2获得锁-0 t2获得锁-1 t1获得锁-0 t1获得锁-1 t1获得锁-2 t2获得锁-2
    //公平锁
    t1获得锁-0 t2获得锁-0 t1获得锁-1 t2获得锁-1 t1获得锁-2 t2获得锁-2

    ReentrantLock公平锁
     
    3、ReentrantLock实现线程通信
    /**
     * 模拟生产者消费者模式-线程之间通信 synchronized-notifyAll/wait
     * @author qiuyongAaron
     */
    public class MyContainerOne {
         LinkedList<Integer> list=new LinkedList<Integer>();
          static final int MAX=10;
          int count=0;
    
      </span><span style="color: #008000;">//</span><span style="color: #008000;">生产者线程</span>
      <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">synchronized</span> <span style="color: #0000ff;">void</span> put(<span style="color: #0000ff;">int</span><span style="color: #000000;"> i){
            </span><span style="color: #0000ff;">while</span>(list.size()==<span style="color: #000000;">MAX){
                 </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
                     </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.wait();
                } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) {
                     e.printStackTrace();
                }
            }
            list.add(i);
            </span>++<span style="color: #000000;">count;
            </span><span style="color: #0000ff;">this</span>.notifyAll();<span style="color: #008000;">//</span><span style="color: #008000;">通知消费者来消费</span>
    

    }

      </span><span style="color: #008000;">//</span><span style="color: #008000;">消费者线程</span>
      <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">synchronized</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> get(){
            </span><span style="color: #0000ff;">while</span>(list.size()==0<span style="color: #000000;">){
                 </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
                     </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.wait();
                } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) {
                     e.printStackTrace();
                }
            }
            </span><span style="color: #0000ff;">int</span> num=<span style="color: #000000;">list.removeFirst();
            count</span>--<span style="color: #000000;">;
            </span><span style="color: #0000ff;">this</span>.notifyAll();<span style="color: #008000;">//</span><span style="color: #008000;">通知生产者生产</span>
            <span style="color: #0000ff;">return</span><span style="color: #000000;"> num;
      }
    
      </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) {
           MyContainerOne container</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> MyContainerOne();
    
           </span><span style="color: #008000;">//</span><span style="color: #008000;">制造10个消费者</span>
           <span style="color: #0000ff;">for</span>(<span style="color: #0000ff;">int</span> i=0;i&lt;10;i++<span style="color: #000000;">){
                </span><span style="color: #0000ff;">new</span> Thread(()-&gt;<span style="color: #000000;">{
                     </span><span style="color: #0000ff;">for</span>(<span style="color: #0000ff;">int</span> j=0;j&lt;5;j++<span style="color: #000000;">) System.out.println(container.get());
                     },
                </span>"c"+<span style="color: #000000;">i).start();
           }
    
           </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
                TimeUnit.SECONDS.sleep(</span>2<span style="color: #000000;">);
           } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) {
                e.printStackTrace();
           }
    
           </span><span style="color: #008000;">//</span><span style="color: #008000;">制造2个生产者</span>
           <span style="color: #0000ff;">for</span>(<span style="color: #0000ff;">int</span> i=0;i&lt;2;i++<span style="color: #000000;">){
                </span><span style="color: #0000ff;">new</span> Thread(()-&gt;<span style="color: #000000;">{
                     </span><span style="color: #0000ff;">for</span>(<span style="color: #0000ff;">int</span> j=0;j&lt;25;j++<span style="color: #000000;">) container.put(j);
                     },
                </span>"p"+<span style="color: #000000;">i).start();
           }
     }
    

    }

    /**
     * 模拟生产者消费者模式-reentrantLock-awit/signAll
     * @author qiuyongAaron
     */
    public class MyContainerTwo {
    
     LinkedList</span>&lt;Integer&gt; list=<span style="color: #0000ff;">new</span> LinkedList&lt;Integer&gt;<span style="color: #000000;">();
      </span><span style="color: #0000ff;">static</span> <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">int</span> MAX=10<span style="color: #000000;">;
      </span><span style="color: #0000ff;">int</span> count=0<span style="color: #000000;">;
    
      ReentrantLock lock</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> ReentrantLock();
      Condition producer</span>=<span style="color: #000000;">lock.newCondition();
      Condition consumer</span>=<span style="color: #000000;">lock.newCondition();
    
      </span><span style="color: #008000;">//</span><span style="color: #008000;">生产者线程</span>
      <span style="color: #0000ff;">public</span>  <span style="color: #0000ff;">void</span> put(<span style="color: #0000ff;">int</span><span style="color: #000000;"> i){
            </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
                 lock.lock();
                 </span><span style="color: #0000ff;">while</span>(list.size()==<span style="color: #000000;">MAX){
                     producer.await();
                 }
                 list.add(i);
                 </span>++<span style="color: #000000;">count;
                 consumer.signalAll();</span><span style="color: #008000;">//</span><span style="color: #008000;">通知消费者来消费</span>
            } <span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e){
                 e.printStackTrace();
            }</span><span style="color: #0000ff;">finally</span><span style="color: #000000;">{
                 lock.unlock();
            }
      }
    
      </span><span style="color: #008000;">//</span><span style="color: #008000;">消费者线程</span>
      <span style="color: #0000ff;">public</span>  <span style="color: #0000ff;">int</span><span style="color: #000000;"> get(){
            </span><span style="color: #0000ff;">try</span><span style="color: #000000;">{
                 lock.lock();
                 </span><span style="color: #0000ff;">while</span>(list.size()==0<span style="color: #000000;">){
                      consumer.await();
                 }
                 </span><span style="color: #0000ff;">int</span> num=<span style="color: #000000;">list.removeFirst();
                 count</span>--<span style="color: #000000;">;
                 producer.signalAll();</span><span style="color: #008000;">//</span><span style="color: #008000;">通知生产者生产</span>
                 <span style="color: #0000ff;">return</span><span style="color: #000000;"> num;
            }</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">(Exception e){
                 e.printStackTrace();
            }</span><span style="color: #0000ff;">finally</span><span style="color: #000000;">{
                 lock.unlock();
            }
            </span><span style="color: #0000ff;">return</span> 0<span style="color: #000000;">;
      }
    
      </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) {
           MyContainerTwo container</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> MyContainerTwo();
    
           </span><span style="color: #008000;">//</span><span style="color: #008000;">制造10个消费者</span>
           <span style="color: #0000ff;">for</span>(<span style="color: #0000ff;">int</span> i=0;i&lt;10;i++<span style="color: #000000;">){
                </span><span style="color: #0000ff;">new</span> Thread(()-&gt;<span style="color: #000000;">{
                     </span><span style="color: #0000ff;">for</span>(<span style="color: #0000ff;">int</span> j=0;j&lt;5;j++<span style="color: #000000;">) System.out.println(container.get());
                     },
                </span>"c"+<span style="color: #000000;">i).start();
           }
    
           </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
                TimeUnit.SECONDS.sleep(</span>2<span style="color: #000000;">);
           } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) {
                e.printStackTrace();
           }
    
           </span><span style="color: #008000;">//</span><span style="color: #008000;">制造2个生产者</span>
           <span style="color: #0000ff;">for</span>(<span style="color: #0000ff;">int</span> i=0;i&lt;2;i++<span style="color: #000000;">){
                </span><span style="color: #0000ff;">new</span> Thread(()-&gt;<span style="color: #000000;">{
                     </span><span style="color: #0000ff;">for</span>(<span style="color: #0000ff;">int</span> j=0;j&lt;25;j++<span style="color: #000000;">) container.put(j);
                     },
                </span>"p"+<span style="color: #000000;">i).start();
           }
     }
    

    }

    总结:synchronized实现线程的消费者-生产者模式是通过wait/notifyAll实现,ReentrantLock是通过condition+await/signAll。那他们有什么区别呢?synchronized要么通过notify随机唤醒一个,或者notifyAll唤醒所有不管你是消费者还是生产者、而ReentrantLock是唤醒指定的线程的,更加精确效率更高。

    四、版权声明

      作者:邱勇Aaron

      出处:http://www.cnblogs.com/qiuyong/

      您的支持是对博主深入思考总结的最大鼓励。

      本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,尊重作者的劳动成果。

      参考:马士兵并发编程、并发编程实践

         AQS详解:http://www.cnblogs.com/waterystone/p/4920797.html

  • 相关阅读:
    用 C# 获取 IE 临时文件(转)
    vs2008打包程序需要.net3.5支持问题的解决方案
    关于使用ssh账号上外网
    元数据管理技术及发展应用现状
    一个拨号上网的批处理文件
    windows下启动和关闭oracle数据库的bat脚本
    Solaris下配置网络
    开启windows 2000 server上的远程桌面
    FileZilla客户端使用TIPs
    学习使用gvim
  • 原文地址:https://www.cnblogs.com/qiuyong/p/7102779.html
Copyright © 2011-2022 走看看