Lock应用之 线程协作

内部锁(对象监视器)使用Object类的wait(), notify(), notifyAll()方法来进行线程之间的协作通信;Lock锁引入Condition来支持线程之间通信协作,Condition提供await(), signal(), signalAll()方法实现与内部锁同样的等待与唤醒功能,但与内部锁不同的是一个Lock可以绑定多个Condition,以满足不同条件下唤醒不同线程的功能。


最典型的线程协作例子就是生产者与消费者。如果使用内部锁控制线程通信,所有线程,不管生产者还是消费者,都被同一个对象监视,当新生产的对象放入消费队列后,生产者会唤醒所有的线程,包括其它生产者,这时队列可能已经满了,所以被唤醒的生产者只好继续回头进入等待队列,一直轮询直到唤醒一个消费者才会进行消费,然后继续。因为Lock支持绑定多个Condition,所以如果使用Lock实现,可以为当队列有对象可消费创建一个Condition,当队列有空位创建一个Condition,这样,生产者和消费者可以相互明确告知,而不是像内部锁广播的方式而缺乏明确的目标对象。


简而言之,内部锁的notify()与notifyAll()会唤醒任何一个线程,不管线程的等待条件是否已经满足;Condition则提供了针对不同类型线程定制唤醒条件的实现,减少无谓的唤醒。


另外,经过测试,在多核情况下,一个线程还可能被一些其它的条件唤醒,所以测试结果并不一定会满意,有待细究。


内部锁与Lock方式实现的生产者与消费者代码案例:

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestLockCondition {
    private static final int MAX_SIZE = 3;
    private static final int PRODUCER_NUM = 5;
    private static final int CONSUMER_NUM = 1;
    private Queue<Object> queue = new LinkedList<Object>();
    private volatile boolean isWorkingTime = true;
    private volatile boolean isUsingLock = true;
    private Lock lock = new ReentrantLock();
    private Condition full = lock.newCondition();  
    private Condition empty = lock.newCondition();
      
    private void produceWithLock() throws InterruptedException{
        lock.lock();
        try{
            while(queue.size() >= MAX_SIZE){
                System.out.println(Thread.currentThread().getName() + " go wait.");
                full.await();
                System.out.println(Thread.currentThread().getName() + " was awaken.");
            }
                      
            queue.offer(new Object());
            System.out.println(Thread.currentThread().getName() + " produce one object.");
            empty.signalAll();
            //empty.signal();
        }
        finally{
            lock.unlock();
        }              
    }
      
    private void consumeWithLock() throws InterruptedException{
        lock.lock();
        try{
            while(queue.isEmpty()){
                System.out.println(Thread.currentThread().getName() + " go wait.");
                empty.await();
                System.out.println(Thread.currentThread().getName() + " was awaken.");
            }
                      
            queue.poll();
            System.out.println(Thread.currentThread().getName() + " consume one object.");
            full.signalAll();
            //full.signal();
        }
        finally{
            lock.unlock();
        }              
    }
      
    private synchronized void produce() throws InterruptedException{
        while(queue.size() >= MAX_SIZE){
            System.out.println(Thread.currentThread().getName() + " go wait.");
            wait();
            System.out.println(Thread.currentThread().getName() + " was awaken.");
        }
                  
        queue.offer(new Object());
        System.out.println(Thread.currentThread().getName() + " produce one object.");
        //notifyAll();
        notify();
    }
      
    private synchronized void consume() throws InterruptedException{
        while(queue.isEmpty()){
            System.out.println(Thread.currentThread().getName() + " go wait.");
            wait();
            System.out.println(Thread.currentThread().getName() + " was awaken.");
        }
                  
        queue.poll();
        System.out.println(Thread.currentThread().getName() + " consume one object.");
        //notifyAll();
        notify();
    }
      
    public static void main(String[] args) throws InterruptedException {
        TestLockCondition testLockCondition = new TestLockCondition();
          
        Thread[] producers = new Thread[PRODUCER_NUM];
          
        for(int i=0; i<PRODUCER_NUM; i++){
            producers[i] = new Thread(testLockCondition.new Producer());
            producers[i].start();
        }      
          
        Thread[] consumers = new Thread[CONSUMER_NUM];
        for(int i=0; i<CONSUMER_NUM; i++){
            consumers[i] = new Thread(testLockCondition.new Consumer());
            consumers[i].start();
        }
          
        TimeUnit.SECONDS.sleep(10);
          
        for(int i=0; i<PRODUCER_NUM; i++){
            System.out.println(producers[i].getName() + " : " + producers[i].getState());
            producers[i].interrupt();
        }
          
        for(int i=0; i<CONSUMER_NUM; i++){
            System.out.println(consumers[i].getName() + " : " + consumers[i].getState());
            consumers[i].interrupt();
        }
                  
        testLockCondition.isWorkingTime = false;
    }
      
    private class Consumer implements Runnable{
        @Override
        public void run() {
            try {
                while(isWorkingTime){
                    if(isUsingLock){
                        //System.out.println(Thread.currentThread().getName() + " is using Lock.");
                        consumeWithLock();
                    }
                    else{
                        consume();
                    }                  
                }              
            } catch (InterruptedException e) {
                e.printStackTrace();
            }          
        }
          
    }
    private class Producer implements Runnable{
        @Override
        public void run() {
            try {
                while(isWorkingTime){
                    if(isUsingLock){
                        //System.out.println(Thread.currentThread().getName() + " is using Lock.");
                        produceWithLock();
                    }
                    else{
                        produce();
                    }
                }              
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
          
    }
}


你可能感兴趣的:(synchronized,wait,notify,Signal)