java 大道至简--多线程(12)

java 大道至简--多线程(12) 

写在前面:有人问我,为什么这几篇没有前面几篇详细,我这里解释一下,不是我偷懒,因为这几篇的内容,是给我们另一种解决多线程的方式,没有所谓最好的方法,更多的是要考自己的领悟,是动手敲出来的,我希望观看此文章的读者能够自己动手,然后自己总结,可能收获会更大

内容目录:

Condition接口

正文:

前面一篇 我们讨论Lock接口的时候提到了  可以对 线程挂起状态进行操作,操作线程挂起状态,Condition接口就是对线程挂起状态操作的类

我们先简单的了解一下,什么是线程挂起状态:简单点说,就是让线程不运行的一种状态,叫挂起

前面我们在将线程基础的时候,我们提了让线程挂起的几个函数,我们再来一起简单的回顾一下:

public void sleep()/sleep(long millis , int nano); 睡眠

public void join()/join(long millis , int nano);  等待结束

public void yield(); 暂停

public void notify(); 休眠

扫描二维码关注公众号,回复: 1708654 查看本文章

具体的使用我这里就不过多的阐述了,在作者的前面几篇博客中我做了简单的讲解,在后面的博文中我们还会继续讲解

上面的这些函数都可以操作线程 让它处于挂起状态,使用Condition也能达到相同的效果,我们先来了解一下Condition这个类的一些常用的函数

public void await(); --   

public boolean await(long time , TimeUnit unit);

public long awaitNanos(long nanos);

public void awaitUninterruptibly();

public boolean awaitUntil(Date deadline);

public void signal();

public void signalAll();

实例:

package test3;


import java.util.concurrent.locks.ReentrantLock;


import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class T  {


   public static void main(String[] args) throws InterruptedException{
      ItemQueue itemQueue = new ItemQueue(10);


      //Create a producer and a consumer.
      Thread producer = new Producer(itemQueue);
      Thread consumer = new Consumer(itemQueue);


      //Start both threads.
      producer.start();
      consumer.start();


      //Wait for both threads to terminate.
      producer.join();
      consumer.join();
   }


   static class ItemQueue {


      private Object[] items = null;
      private int current = 0;
      private int placeIndex = 0;
      private int removeIndex = 0;


      private final Lock lock;
      private final Condition isEmpty;
      private final Condition isFull;


      public ItemQueue(int capacity) {
         this.items = new Object[capacity];
         lock = new ReentrantLock();
         isEmpty = lock.newCondition();
         isFull = lock.newCondition();
      }


      public void add(Object item) throws InterruptedException {
         lock.lock();
         while(current >= items.length)
            isFull.await();


         items[placeIndex] = item;


         placeIndex = (placeIndex + 1) % items.length;


         ++current;


         //Notify the consumer that there is data available.
         isEmpty.signal();


         lock.unlock();
      }


      public Object remove() throws InterruptedException {
         Object item = null;


         lock.lock();
         while(current <= 0){
            isEmpty.await();
         }
         item = items[removeIndex];


         removeIndex = (removeIndex + 1) % items.length;


         --current;


         //Notify the producer that there is space available.
         isFull.signal();
         lock.unlock();


         return item;
      }


      public boolean isEmpty(){
         return (items.length == 0);
      }
   }


   static class Producer extends Thread {


      private final ItemQueue queue;
      public Producer(ItemQueue queue) {
         this.queue = queue;
      }


      @Override
      public void run() {
         String[] numbers = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"};


         try {
            for(String number: numbers){
               queue.add(number);
               System.out.println("[Producer]: " + number);
            }
            queue.add(null);
         }
         catch (InterruptedException ex) {
            ex.printStackTrace();
         } 
      }
   }


   static class Consumer extends Thread {


      private final ItemQueue queue;
      public Consumer(ItemQueue queue) {
         this.queue = queue;
      }


      @Override
      public void run() {
         try {
            do {
               Object number = queue.remove();
               System.out.println("[Consumer]: " + number);
               if(number == null){
                  return;
               }
            } while(!queue.isEmpty());
         }
         catch (InterruptedException ex) {
            ex.printStackTrace();
         }
      }
   }
}


现在我们在思考一下Object中wait函数的作用:

Object wait(); 让线程休眠,直到调用notify()或者notifyAll()才有可能执行,那么请各位思考下面的这个场景:

线程1 : synchronized(obj){

      obj.wait(); 

}

线程2: synchronized(obj){

    obj.wait();

}

线程3:synchronized(obj){

 obj.notify(); 

}

假设现在我们的执行想要执行的顺序是1-->3-->2(先wait然后notify),那么试想当3 notify运行之后2一定会执行吗?答案是不一定的,这个就要看那个线程的优先级高了,如果是一样的优先级那么他们竞争CPU是一样的,也就是1和2是都有可能执行的,这就是普通方法挂起线程的缺点,为了解决这种问题,我们就可以使用Condition中的挂起状态了

例如:

ReentrantLock r1 = new ReentrantLock(true);  表示各个线程之间可以公平的竞争锁

Condition c1 = r1.newCondition();

Condition c2 = r1.newCondition();

线程1: 

r1.lock;

c1.await(); // 第一把锁

r1.unlock();


线程2:

r2.lock();

c2.await(); //第二把锁

r2.unlock();


线程3:

r3.lock();

c1.signal(); //唤醒第一把锁,继续运行线程1await()之后的脚本

r3.unlock();

由此可以看出得出结论:

Object 因为锁是同一个对象,所以在处理线程挂起状态的时候,不是特别灵活

Condition可以添加多个锁操作对象,所以更加灵活





猜你喜欢

转载自blog.csdn.net/xianghan_qq/article/details/80761284