Java多线程之Lock

多线程之 Lock接口

  1. 在synchronized的同步机制下,一个锁对象只能对应一组监视器方法,若要提供多组监视器,则必须有多个锁对象,这种情况下锁会相互嵌套,容易引发死锁问题,利用同步实现多生产多消费问题时,只能利用notifyAll()唤醒全部等待中的线程,无法实现本方只唤醒对方,这降低了程序的效率。
  2. 在jdk1.5之后提供了Lock锁机制,位于java.util.concurrent.locks包下,Lock中将Object类中的监视器方法(wait()notify()notifyAll()单独封装成为了Condition对象中的(await()signal()signalAll()),并且一个锁对象可以创建多个监视器对象(通过调用Lock的newCondition方法),ReentrantLock类是实现了Lock接口的子类,通过该子类对象为Lock接口实例化,创建锁对象。

Lock锁机制的规范使用格式:
将锁对象的释放置于finally块中,是以防在执行释放锁语句之前程序出现异常,导致无法释放锁资源。

//实例化锁对象
Lock lock = new ReentrantLock();
//实例化监视器
Condition condition = lock.newCondition();

lock.lock(); // 上锁
try {
	... // 处理代码,在这之间根据需要有监视器方法的调用
} finally {
	lock.unlock(); // 释放锁
}

应用实例:多生产多消费

package thread类测试.lock锁机制;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
 * 多线程应用情景2:
 * 	多生产多消费者问题
	 * 问题1:生产了商品没有被消费,同一个商品被消费多次
	 * 产生原因:被唤醒的线程没有判断标记,造成问题1的产生。
	 * 解决:只要让被唤醒的线程必须判断标记就可以了,即将if判断标记的方式更改为while判断标记的方式。**记住:多生产多消费,必须使用while判断标记。**
	 * 问题2:加入while判断后,出现了死锁。
	 * 产生原因:生产方唤醒了线程池中等待的生产方的线程,即本方唤醒了本方。
 * 解决:希望本方要唤醒对方,利用Lock来实例化不同的监视器,从而实现本方唤醒对方。
 * 此种解决方案解决了问题2,并且解决了synchronized唤醒全部等待中线程遗留的效率问题。
 * 
 * 2018年9月30日下午4:03:21
 */
public class ProducerConsumer4 {
	public static void main(String[] args) {
		//1、创建资源对象
		Resource r = new Resource();
		//2、创建线程任务
		Producer pro = new Producer(r);
		Consumer con = new Consumer(r);
		//3、创建线程
		Thread t1 = new Thread(pro);
		Thread t2 = new Thread(pro);
		Thread t3 = new Thread(con);
		Thread t4 = new Thread(con);
		//4、启动线程
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}
//1、描述资源。属性:商品名称和编号;行为:对商品名称赋值,获取商品
class Resource{	
	private String name;
	private int count = 1;	
	Lock lock = new ReentrantLock();
	//实例化生产者监视器
	Condition produce = lock.newCondition();
	//实例化消费者监视器
	Condition consume = lock.newCondition();	
	//定义标记,false表示没有商品,true表示有商品待消费
	private boolean flag = false;	
	public String getName() { //供消费者调用
		lock.lock();
		try {
			while(!flag) {
				try {
					consume.await();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			System.out.println(Thread.currentThread()+".....消费了..."+this.name);
			//消费了商品,修改标记
			flag = false;
			//唤醒生产者,只需要唤醒其中一个生产者即可,提高了程序的效率
			produce.signal();
		} finally {
			lock.unlock();
		}
		return name;
	}	
	public void setName(String name) { //供生产者调用
		lock.lock();
		try {
			while(flag) {
				try {
					produce.await();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			this.name = name + this.count;
			this.count++;
			System.out.println(Thread.currentThread()+"...生产了..."+this.name);
			//生产了商品,修改标记
			flag = true;
			//唤醒消费者,只需要唤醒其中一个消费者即可,提高了程序的效率
			consume.signal();
		}finally {
			lock.unlock();
		}
	}	
}
//2、描述生产者
class Producer implements Runnable {
	private Resource r;
	//生产者一初始化就要有资源,需要将资源传递到构造方法中
	public Producer(Resource r) {
		this.r = r;
	}
	@Override
	public void run() {
		for(int i=0;i<50;i++) {
			r.setName("面包");
		}
	}	
}
//3、描述消费者
class Consumer implements Runnable {
	private Resource r;
	//消费者一初始化就要有资源,需要将资源传递到构造方法中
	public Consumer(Resource r) {
		this.r = r;
	}
	@Override
	public void run() {
		for(int i=0;i<50;i++) {
			r.getName();
		}
	}	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值