ReentrantLock简单介绍和使用ReentrantLock实现生产者消费者模式


/**
 * 1,ReentrantLock和synchronized都是可重入锁,Reentrant的本意就是“可重入的”。可重入锁顾名思义,就是在拥有锁的情况下可以调用其它需要本锁的方法或者代码块
 * (同一个锁对象)
 *,2,synchronized只能实现非公平锁,ReentrantLock可以实现公平锁和非公平锁。公平锁或者非公平锁,顾名思义就是线程获取锁的顺序是否和加锁的顺序一致。ReentrantLock
 * 默认的构造方法创建的是非公平锁,ReentrantLock(true)创建的是公平锁。因为公平锁是将线程放到一个队列里面按次序进行调度(FIFO),因此性能比较低。
 * 3,ReentrantLock的锁必须手动释放,即调用unlock()方法释放锁,否则一直阻塞。释放锁的代码最好在finally代码块中进行,因为ReentrantLock发生异常时不会释放锁,而synchronized
 * 修饰的代码块发生异常时可以释放锁。
 * 4,synchronized与wait()/notify()、notifyAll()方法相结合可以实现线程间的通信。ReentrantLock和Condition配合能实现类似的功能,并且功能更强大。
 * ReentrantLock和Condition的组合可以唤醒某个特定的线程,而synchronized唤醒哪个线程,是不确定的。
 * 5,synchronized锁对象的wait()方法相当于Condition的await()方法,会释放锁,线程进入阻塞状态。
 *  synchronized锁对象的wait(long)方法相当于Condition类的await(long)方法,多少秒之后才进入阻塞状态并释放锁。
 *  synchronized锁对类的notify()方法相当于Condition的signal()方法,notifyAll()方法相当于Condition类的signalAll()方法,唤醒等待的线程
 * 6,参考博客:https://www.cnblogs.com/qlqwjy/p/10130454.html,感谢作者
 *
 */
public class ReentrantLockTest {
   List list=new ArrayList();
   //创建锁
	private  Lock lock=new ReentrantLock();
	
	private Condition consumerCd = lock.newCondition();
	private Condition producterCd = lock.newCondition();
	
	/**
	 * 创建两个消费者线程,两个生产者线程
	 */
	public void f1() {
		Thread consumer1=new Thread(new Runnable() {
			@Override
			public void run() {
				consumeMethod();
			}
		},"消费者1");
		
		Thread consumer2=new Thread(new Runnable() {
			@Override
			public void run() {
				consumeMethod();
				
			}
		},"消费者2");
		
		Thread producter1=new Thread(new Runnable() {
			@Override
			public void run() {
				productMethod();
				
			}
		},"生产者1");
		
		Thread producter2=new Thread(new Runnable() {
			@Override
			public void run() {
				productMethod();
				
			}
		},"生产者2");
		
		consumer1.start();
		consumer2.start();
		producter1.start();
		producter2.start();
		
	}
	
	/**
	 * 消费方法
	 * 如果数组长度大于0,则消费者线程消费一个元素。否则给生产者线程发信号唤醒生产者进行生产,自己等待。
	 */
	public void consumeMethod(){
		try {
			lock.lock();
			while(true){
				if(list.size()>0){
					System.out.println(Thread.currentThread().getName()+"消费了一个产品:"+list.get(0));
					list.remove(0);
				}else{
					//signal()方法要在await()方法之前执行,因为await()方法是阻塞的,一旦await()方法先执行,signal()方法就不能及时执行。
					producterCd.signal();
					consumerCd.await();
				}
			}
			
		} catch (Exception e) {
			
		}finally{
			lock.unlock();
		}
	}
	/**
	 * 生产方法
	 * 如果数组长度等于0,生产者线程则生产一个元素,并给消费者线程发信号唤醒消费者进行消费,自己等待
	 */
	public void productMethod(){
		try {
			lock.lock();
			Random random=new Random();
			while(true){
				if(list.size()==0){
					int value=random.nextInt(100);
					list.add(value);
					System.out.println(Thread.currentThread().getName()+"生产了一个产品:"+value);
					consumerCd.signal();
				}else{
					producterCd.await();
				}
			}
			
		} catch (Exception e) {
			
		}finally{
			lock.unlock();
		}
		
	}

	public static void main(String[] args) {
		ReentrantLockTest reentrantLockTest=new ReentrantLockTest();
		reentrantLockTest.f1();
	}
}

控制台输出(部分数据):
 

生产者2生产了一个产品:61
消费者1消费了一个产品:61
生产者1生产了一个产品:27
消费者2消费了一个产品:27
生产者2生产了一个产品:41
消费者1消费了一个产品:41
生产者1生产了一个产品:33
消费者2消费了一个产品:33
生产者2生产了一个产品:40
消费者1消费了一个产品:40
生产者1生产了一个产品:43
消费者2消费了一个产品:43
生产者2生产了一个产品:47
消费者1消费了一个产品:47
生产者1生产了一个产品:85
消费者2消费了一个产品:85
生产者2生产了一个产品:13
消费者1消费了一个产品:13
生产者1生产了一个产品:66
消费者2消费了一个产品:66
生产者2生产了一个产品:98
消费者1消费了一个产品:98
生产者1生产了一个产品:91
消费者2消费了一个产品:91
生产者2生产了一个产品:72
消费者1消费了一个产品:72
生产者1生产了一个产品:11
消费者2消费了一个产品:11
生产者2生产了一个产品:91
消费者1消费了一个产品:91
生产者1生产了一个产品:78
消费者2消费了一个产品:78
生产者2生产了一个产品:25
消费者1消费了一个产品:25
生产者1生产了一个产品:5
消费者2消费了一个产品:5
生产者2生产了一个产品:6
消费者1消费了一个产品:6
生产者1生产了一个产品:20
消费者2消费了一个产品:20
生产者2生产了一个产品:93
消费者1消费了一个产品:93
生产者1生产了一个产品:31
消费者2消费了一个产品:31
生产者2生产了一个产品:12
消费者1消费了一个产品:12
生产者1生产了一个产品:33
消费者2消费了一个产品:33
生产者2生产了一个产品:25
消费者1消费了一个产品:25
生产者1生产了一个产品:57
消费者2消费了一个产品:57
生产者2生产了一个产品:96
消费者1消费了一个产品:96
生产者1生产了一个产品:9
消费者2消费了一个产品:9
生产者2生产了一个产品:87
消费者1消费了一个产品:87
生产者1生产了一个产品:48
消费者2消费了一个产品:48
生产者2生产了一个产品:41
消费者1消费了一个产品:41
生产者1生产了一个产品:62
消费者2消费了一个产品:62
生产者2生产了一个产品:4
消费者1消费了一个产品:4
生产者1生产了一个产品:63

声明:随手一写,并不严谨,切勿作为参考

你可能感兴趣的:(java)