Java多线程并发访问同步代码块:Lock使用简述

本文介绍了Java并发编程中Lock接口及其实现类ReentrantLock相较于synchronized的使用优势。通过示例展示了如何在库存管理中使用ReentrantLock实现线程安全,强调了Lock的使用规范,包括获取和释放锁的try-finally结构,以及其在避免死锁方面的优势。
摘要由CSDN通过智能技术生成

概述

java并发包中的Lock接口及其实现类,相对较早的synchronized关键字的代码块,提供了对同步代码块的另一种机制,相对来说更强大也更灵活。

使用synchronized关键字时,只能在同一个synchronized代码块中获取和释放控制。而Lock接口允许实现更复杂的代码块结构,即控制的获取和释放不必出现在同一个块结构中。

相对Lock接口来说,如果使用synchronized关键字不恰当,会造成死锁的可能性会更高,Lock接口使用起来则更简单直观,推荐使用。

Lock接口及其实现类(基于jdk8)继承结构如下:

最佳实践

有java开发经验的人,都知道,遵循api使用规则,将事半功倍,那么Lock接口也不例外:

Lock l = ...; // 声明你的锁对象(实现类)

l.lock(); //开启锁
try { 
    // 这里是你的业务逻辑代码 
} finally { 

    l.unlock(); //关闭锁
} 

示例

如下示例一个库存控制处理类和模拟用户购物的用户线程类:

库存控制处理类:Stock.java:

public class Stock {
	
	private final Lock stockLock = new ReentrantLock();
	// 库存假定总量
	private int total = 20;
	
	public void compute(int num) {
		
		stockLock.lock();
		
		try {
			
			System.out.println("\nStock current total : " + total + ", for" + Thread.currentThread().getName() + " buy shop goods number=" + num);
			// 库存判断
			if (total < 1 || total < num) {
				System.out.print("库存不足!");
				System.out.println("So, Buyer : " + Thread.currentThread().getName() + " give up!");
				return;
			}
			//库存业务逻辑处理...
			systemProcess(num);
			
		} catch (InterruptedException e) {
			System.out.println("Stock process causes exception : " + e);
			e.printStackTrace();
		} finally {
			stockLock.unlock();
		}
	}

	private void systemProcess(int num) throws InterruptedException {
		int workSecond = new Random().nextInt(2) + 1;
		System.out.println("Shopper system processed cost : " + workSecond);
		TimeUnit.SECONDS.sleep(workSecond);
		total -= num;
		System.out.println("Stock now remain : " + total);
	}
}

购买商品的用户线程类:Buyer.java:

public class Buyer implements Runnable {
	
	private Stock s;

	public Buyer(Stock s, String name, int shopNum) {
		super();
		this.name = name;
		this.shopNum = shopNum;
		this.s = s;
	}

	private String name; // 购买用户姓名
	private int shopNum; // 购买的数量

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}


	public int getShopNum() {
		return shopNum;
	}

	public void setShopNum(int shopNum) {
		this.shopNum = shopNum;
	}

	@Override
	public void run() {
        // 调用库存处理类业务逻辑
		s.compute(shopNum);
	}
}

测试类:

public class ReentrantLockTest{

	
	public static void main(String[] args) {
			String[] names = { "Rose" , "Jack", "Tommy", "Blank", "Mary", "Lydia", "Mike" };
			int userNum = names.length;
			// 新建并发购买商品的用户线程
			Thread[] users = new Thread[userNum];
			Stock stock = new Stock();
			for (int i = 0; i < userNum; i++) {
				String currentUserName = names[i];
                // 注意这里的stock:公用的库存锁,是用户多线程的共享变量
				users[i] = new Thread(new Buyer(stock, currentUserName, 
                                getRandomShopNum(currentUserName)), currentUserName);
			}
			
			// 启动购买商品的用户线程
			for (int j = 0; j < userNum; j++) {
				users[j].start();
			}
	}
	
	private static int getRandomShopNum(String userName) {
		int num = new Random().nextInt(6) + 1;
		System.out.println("User : " + userName + " wanna buy shop goods number=" + num);
		return num;
	}
}

测试日志:

User : Rose wanna buy shop goods number=5
User : Jack wanna buy shop goods number=6
User : Tommy wanna buy shop goods number=3
User : Blank wanna buy shop goods number=5
User : Mary wanna buy shop goods number=3
User : Lydia wanna buy shop goods number=5
User : Mike wanna buy shop goods number=6

Stock current total : 20, forRose buy shop goods number=5
Shopper system processed cost : 2
Stock now remain : 15

Stock current total : 15, forJack buy shop goods number=6
Shopper system processed cost : 1
Stock now remain : 9

Stock current total : 9, forTommy buy shop goods number=3
Shopper system processed cost : 1
Stock now remain : 6

Stock current total : 6, forBlank buy shop goods number=5
Shopper system processed cost : 2
Stock now remain : 1

Stock current total : 1, forMary buy shop goods number=3
库存不足!So, Buyer : Mary give up!

Stock current total : 1, forLydia buy shop goods number=5
库存不足!So, Buyer : Lydia give up!

Stock current total : 1, forMike buy shop goods number=6
库存不足!So, Buyer : Mike give up!

小结

如上示例,使用Lock接口实现多用户购买并发对同一个商品访问,为了让用户购买成功,需要保证同一时间只有一个用户线程进行对库存的扣减,那么先必须声明及创建一个Lock对象(这里用的是实现类:ReentrantLock对象)。

然后,通过lock()方法获取对锁的控制,当用户A访问这个方法时,如果没有其他用户获取对这个锁的控制,那么lock()方法将让用户A获得锁并且允许执行这段代码块,否则若有其他用户,如用户B在执行这个锁控制的代码块,lock()方法将让用户A暂时“休眠”,直到用户B执行完这段代码块。

最后,切记要释放锁!

Good Luck!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值